pax_global_header00006660000000000000000000000064126210257420014513gustar00rootroot0000000000000052 comment=15e800f0fc759fea72d982e9a491cf8206bc5f74 partclone-0.2.86/000077500000000000000000000000001262102574200135775ustar00rootroot00000000000000partclone-0.2.86/.gitattributes000066400000000000000000000000331262102574200164660ustar00rootroot00000000000000src/version.h export-subst partclone-0.2.86/.gitignore000066400000000000000000000011611262102574200155660ustar00rootroot00000000000000*.o */Makefile Makefile autom4te.cache/ config.h config.log config.status get_lib_version po/Makefile.in fail-mbr/fail-mbr.bin fail-mbr/fail-mbr.image src/.deps/ src/partclone.btrfs src/partclone.fstype src/partclone.jfs src/partclone.ufs src/partclone.vmfs src/partclone.vmfs5 src/partclone.chkimg src/partclone.dd src/partclone.imager src/partclone.exfat src/partclone.extfs src/partclone.fat src/partclone.hfsp src/partclone.info src/partclone.ntfs src/partclone.ntfsfixboot src/partclone.reiser4 src/partclone.reiserfs src/partclone.restore src/partclone.xfs src/partclone.minix src/partclone.f2fs src/version.h stamp-h1 partclone-0.2.86/ABOUT-NLS000066400000000000000000002333401262102574200150330ustar00rootroot000000000000001 Notes on the Free Translation Project *************************************** Free software is going international! The Free Translation Project is a way to get maintainers of free software, translators, and users all together, so that free software will gradually become able to speak many languages. A few packages already provide translations for their messages. If you found this `ABOUT-NLS' file inside a distribution, you may assume that the distributed package does use GNU `gettext' internally, itself available at your nearest GNU archive site. But you do _not_ need to install GNU `gettext' prior to configuring, installing or using this package with messages translated. Installers will find here some useful hints. These notes also explain how users should proceed for getting the programs to use the available translations. They tell how people wanting to contribute and work on translations can contact the appropriate team. When reporting bugs in the `intl/' directory or bugs which may be related to internationalization, you should tell about the version of `gettext' which is used. The information can be found in the `intl/VERSION' file, in internationalized packages. 1.1 Quick configuration advice ============================== If you want to exploit the full power of internationalization, you should configure it using ./configure --with-included-gettext to force usage of internationalizing routines provided within this package, despite the existence of internationalizing capabilities in the operating system where this package is being installed. So far, only the `gettext' implementation in the GNU C library version 2 provides as many features (such as locale alias, message inheritance, automatic charset conversion or plural form handling) as the implementation here. It is also not possible to offer this additional functionality on top of a `catgets' implementation. Future versions of GNU `gettext' will very likely convey even more functionality. So it might be a good idea to change to GNU `gettext' as soon as possible. So you need _not_ provide this option if you are using GNU libc 2 or you have installed a recent copy of the GNU gettext package with the included `libintl'. 1.2 INSTALL Matters =================== Some packages are "localizable" when properly installed; the programs they contain can be made to speak your own native language. Most such packages use GNU `gettext'. Other packages have their own ways to internationalization, predating GNU `gettext'. By default, this package will be installed to allow translation of messages. It will automatically detect whether the system already provides the GNU `gettext' functions. If not, the included GNU `gettext' library will be used. This library is wholly contained within this package, usually in the `intl/' subdirectory, so prior installation of the GNU `gettext' package is _not_ required. Installers may use special options at configuration time for changing the default behaviour. The commands: ./configure --with-included-gettext ./configure --disable-nls will, respectively, bypass any pre-existing `gettext' to use the internationalizing routines provided within this package, or else, _totally_ disable translation of messages. When you already have GNU `gettext' installed on your system and run configure without an option for your new package, `configure' will probably detect the previously built and installed `libintl.a' file and will decide to use this. This might not be desirable. You should use the more recent version of the GNU `gettext' library. I.e. if the file `intl/VERSION' shows that the library which comes with this package is more recent, you should use ./configure --with-included-gettext to prevent auto-detection. The configuration process will not test for the `catgets' function and therefore it will not be used. The reason is that even an emulation of `gettext' on top of `catgets' could not provide all the extensions of the GNU `gettext' library. Internationalized packages usually have many `po/LL.po' files, where LL gives an ISO 639 two-letter code identifying the language. Unless translations have been forbidden at `configure' time by using the `--disable-nls' switch, all available translations are installed together with the package. However, the environment variable `LINGUAS' may be set, prior to configuration, to limit the installed set. `LINGUAS' should then contain a space separated list of two-letter codes, stating which languages are allowed. 1.3 Using This Package ====================== As a user, if your language has been installed for this package, you only have to set the `LANG' environment variable to the appropriate `LL_CC' combination. Here `LL' is an ISO 639 two-letter language code, and `CC' is an ISO 3166 two-letter country code. For example, let's suppose that you speak German and live in Germany. At the shell prompt, merely execute `setenv LANG de_DE' (in `csh'), `export LANG; LANG=de_DE' (in `sh') or `export LANG=de_DE' (in `bash'). This can be done from your `.login' or `.profile' file, once and for all. You might think that the country code specification is redundant. But in fact, some languages have dialects in different countries. For example, `de_AT' is used for Austria, and `pt_BR' for Brazil. The country code serves to distinguish the dialects. The locale naming convention of `LL_CC', with `LL' denoting the language and `CC' denoting the country, is the one use on systems based on GNU libc. On other systems, some variations of this scheme are used, such as `LL' or `LL_CC.ENCODING'. You can get the list of locales supported by your system for your language by running the command `locale -a | grep '^LL''. Not all programs have translations for all languages. By default, an English message is shown in place of a nonexistent translation. If you understand other languages, you can set up a priority list of languages. This is done through a different environment variable, called `LANGUAGE'. GNU `gettext' gives preference to `LANGUAGE' over `LANG' for the purpose of message handling, but you still need to have `LANG' set to the primary language; this is required by other parts of the system libraries. For example, some Swedish users who would rather read translations in German than English for when Swedish is not available, set `LANGUAGE' to `sv:de' while leaving `LANG' to `sv_SE'. Special advice for Norwegian users: The language code for Norwegian bokma*l changed from `no' to `nb' recently (in 2003). During the transition period, while some message catalogs for this language are installed under `nb' and some older ones under `no', it's recommended for Norwegian users to set `LANGUAGE' to `nb:no' so that both newer and older translations are used. In the `LANGUAGE' environment variable, but not in the `LANG' environment variable, `LL_CC' combinations can be abbreviated as `LL' to denote the language's main dialect. For example, `de' is equivalent to `de_DE' (German as spoken in Germany), and `pt' to `pt_PT' (Portuguese as spoken in Portugal) in this context. 1.4 Translating Teams ===================== For the Free Translation Project to be a success, we need interested people who like their own language and write it well, and who are also able to synergize with other translators speaking the same language. Each translation team has its own mailing list. The up-to-date list of teams can be found at the Free Translation Project's homepage, `http://www.iro.umontreal.ca/contrib/po/HTML/', in the "National teams" area. If you'd like to volunteer to _work_ at translating messages, you should become a member of the translating team for your own language. The subscribing address is _not_ the same as the list itself, it has `-request' appended. For example, speakers of Swedish can send a message to `sv-request@li.org', having this message body: subscribe Keep in mind that team members are expected to participate _actively_ in translations, or at solving translational difficulties, rather than merely lurking around. If your team does not exist yet and you want to start one, or if you are unsure about what to do or how to get started, please write to `translation@iro.umontreal.ca' to reach the coordinator for all translator teams. The English team is special. It works at improving and uniformizing the terminology in use. Proven linguistic skills are praised more than programming skills, here. 1.5 Available Packages ====================== Languages are not equally supported in all packages. The following matrix shows the current state of internationalization, as of October 2006. The matrix shows, in regard of each package, for which languages PO files have been submitted to translation coordination, with a translation percentage of at least 50%. Ready PO files af am ar az be bg bs ca cs cy da de el en en_GB eo +----------------------------------------------------+ GNUnet | [] | a2ps | [] [] [] [] [] | aegis | () | ant-phone | () | anubis | [] | ap-utils | | aspell | [] [] [] [] [] | bash | [] [] [] | batchelor | [] | bfd | | bibshelf | [] | binutils | [] | bison | [] [] | bison-runtime | | bluez-pin | [] [] [] [] [] | cflow | [] | clisp | [] [] | console-tools | [] [] | coreutils | [] [] [] | cpio | | cpplib | [] [] [] | cryptonit | [] | darkstat | [] () [] | dialog | [] [] [] [] [] [] | diffutils | [] [] [] [] [] [] | doodle | [] | e2fsprogs | [] [] | enscript | [] [] [] [] | error | [] [] [] [] | fetchmail | [] [] () [] | fileutils | [] [] | findutils | [] [] [] | flex | [] [] [] | fslint | [] | gas | | gawk | [] [] [] | gbiff | [] | gcal | [] | gcc | [] | gettext-examples | [] [] [] [] [] | gettext-runtime | [] [] [] [] [] | gettext-tools | [] [] | gimp-print | [] [] [] [] | gip | [] | gliv | [] | glunarclock | [] | gmult | [] [] | gnubiff | () | gnucash | () () [] | gnucash-glossary | [] () | gnuedu | | gnulib | [] [] [] [] [] [] | gnunet-gtk | | gnutls | | gpe-aerial | [] [] | gpe-beam | [] [] | gpe-calendar | | gpe-clock | [] [] | gpe-conf | [] [] | gpe-contacts | | gpe-edit | [] | gpe-filemanager | | gpe-go | [] | gpe-login | [] [] | gpe-ownerinfo | [] [] | gpe-package | | gpe-sketchbook | [] [] | gpe-su | [] [] | gpe-taskmanager | [] [] | gpe-timesheet | [] | gpe-today | [] [] | gpe-todo | | gphoto2 | [] [] [] [] | gprof | [] [] | gpsdrive | () () | gramadoir | [] [] | grep | [] [] [] [] [] [] | gretl | | gsasl | | gss | | gst-plugins | [] [] [] [] | gst-plugins-base | [] [] [] | gst-plugins-good | [] [] [] [] [] [] [] | gstreamer | [] [] [] [] [] [] [] | gtick | () | gtkam | [] [] [] | gtkorphan | [] [] | gtkspell | [] [] [] [] | gutenprint | [] | hello | [] [] [] [] [] | id-utils | [] [] | impost | | indent | [] [] [] | iso_3166 | [] [] | iso_3166_2 | | iso_4217 | [] | iso_639 | [] [] | jpilot | [] | jtag | | jwhois | | kbd | [] [] [] [] | keytouch | | keytouch-editor | | keytouch-keyboa... | | latrine | () | ld | [] | leafpad | [] [] [] [] [] | libc | [] [] [] [] [] | libexif | [] | libextractor | [] | libgpewidget | [] [] [] | libgpg-error | [] | libgphoto2 | [] [] | libgphoto2_port | [] [] | libgsasl | | libiconv | [] [] | libidn | [] [] | lifelines | [] () | lilypond | [] | lingoteach | | lynx | [] [] [] [] | m4 | [] [] [] [] | mailutils | [] | make | [] [] | man-db | [] () [] [] | minicom | [] [] [] | mysecretdiary | [] [] | nano | [] [] [] | nano_1_0 | [] () [] [] | opcodes | [] | parted | | pilot-qof | [] | psmisc | [] | pwdutils | | python | | qof | | radius | [] | recode | [] [] [] [] [] [] | rpm | [] [] | screem | | scrollkeeper | [] [] [] [] [] [] [] [] | sed | [] [] [] | sh-utils | [] [] | shared-mime-info | [] [] [] [] | sharutils | [] [] [] [] [] [] | shishi | | silky | | skencil | [] () | sketch | [] () | solfege | | soundtracker | [] [] | sp | [] | stardict | [] | system-tools-ba... | [] [] [] [] [] [] [] [] [] | tar | [] | texinfo | [] [] [] | textutils | [] [] [] | tin | () () | tp-robot | [] | tuxpaint | [] [] [] [] [] | unicode-han-tra... | | unicode-transla... | | util-linux | [] [] [] [] | vorbis-tools | [] [] [] [] | wastesedge | () | wdiff | [] [] [] [] | wget | [] [] | xchat | [] [] [] [] [] [] | xkeyboard-config | | xpad | [] [] | +----------------------------------------------------+ af am ar az be bg bs ca cs cy da de el en en_GB eo 10 0 1 2 9 22 1 42 41 2 60 95 16 1 17 16 es et eu fa fi fr ga gl gu he hi hr hu id is it +--------------------------------------------------+ GNUnet | | a2ps | [] [] [] () | aegis | | ant-phone | [] | anubis | [] | ap-utils | [] [] | aspell | [] [] [] | bash | [] [] [] | batchelor | [] [] | bfd | [] | bibshelf | [] [] [] | binutils | [] [] [] | bison | [] [] [] [] [] [] | bison-runtime | [] [] [] [] [] | bluez-pin | [] [] [] [] [] | cflow | [] | clisp | [] [] | console-tools | | coreutils | [] [] [] [] [] [] | cpio | [] [] [] | cpplib | [] [] | cryptonit | [] | darkstat | [] () [] [] [] | dialog | [] [] [] [] [] [] [] [] | diffutils | [] [] [] [] [] [] [] [] [] | doodle | [] [] | e2fsprogs | [] [] [] | enscript | [] [] [] | error | [] [] [] [] [] | fetchmail | [] | fileutils | [] [] [] [] [] [] | findutils | [] [] [] [] | flex | [] [] [] | fslint | [] | gas | [] [] | gawk | [] [] [] [] | gbiff | [] | gcal | [] [] | gcc | [] | gettext-examples | [] [] [] [] [] [] | gettext-runtime | [] [] [] [] [] [] | gettext-tools | [] [] [] | gimp-print | [] [] | gip | [] [] [] | gliv | () | glunarclock | [] [] [] | gmult | [] [] [] | gnubiff | () () | gnucash | () () () | gnucash-glossary | [] [] | gnuedu | [] | gnulib | [] [] [] [] [] [] [] [] | gnunet-gtk | | gnutls | | gpe-aerial | [] [] | gpe-beam | [] [] | gpe-calendar | | gpe-clock | [] [] [] [] | gpe-conf | [] | gpe-contacts | [] [] | gpe-edit | [] [] [] [] | gpe-filemanager | [] | gpe-go | [] [] [] | gpe-login | [] [] [] | gpe-ownerinfo | [] [] [] [] [] | gpe-package | [] | gpe-sketchbook | [] [] | gpe-su | [] [] [] [] | gpe-taskmanager | [] [] [] | gpe-timesheet | [] [] [] [] | gpe-today | [] [] [] [] | gpe-todo | [] | gphoto2 | [] [] [] [] [] | gprof | [] [] [] [] | gpsdrive | () () [] () | gramadoir | [] [] | grep | [] [] [] [] [] [] [] [] [] [] [] [] | gretl | [] [] [] | gsasl | [] [] | gss | [] | gst-plugins | [] [] [] | gst-plugins-base | [] [] | gst-plugins-good | [] [] [] | gstreamer | [] [] [] | gtick | [] | gtkam | [] [] [] [] | gtkorphan | [] [] | gtkspell | [] [] [] [] [] [] | gutenprint | [] | hello | [] [] [] [] [] [] [] [] [] [] [] [] [] | id-utils | [] [] [] [] [] | impost | [] [] | indent | [] [] [] [] [] [] [] [] [] [] | iso_3166 | [] [] [] | iso_3166_2 | [] | iso_4217 | [] [] [] [] | iso_639 | [] [] [] [] [] | jpilot | [] [] | jtag | [] | jwhois | [] [] [] [] [] | kbd | [] [] | keytouch | [] | keytouch-editor | [] | keytouch-keyboa... | [] | latrine | [] [] [] | ld | [] [] | leafpad | [] [] [] [] [] [] | libc | [] [] [] [] [] | libexif | [] | libextractor | [] | libgpewidget | [] [] [] [] [] | libgpg-error | | libgphoto2 | [] [] [] | libgphoto2_port | [] [] | libgsasl | [] [] | libiconv | [] [] | libidn | [] [] | lifelines | () | lilypond | [] | lingoteach | [] [] [] | lynx | [] [] [] | m4 | [] [] [] [] | mailutils | [] [] | make | [] [] [] [] [] [] [] [] | man-db | () | minicom | [] [] [] [] | mysecretdiary | [] [] [] | nano | [] [] [] [] [] [] | nano_1_0 | [] [] [] [] [] | opcodes | [] [] [] [] | parted | [] [] [] [] | pilot-qof | | psmisc | [] [] [] | pwdutils | | python | | qof | [] | radius | [] [] | recode | [] [] [] [] [] [] [] [] | rpm | [] [] | screem | | scrollkeeper | [] [] [] | sed | [] [] [] [] [] | sh-utils | [] [] [] [] [] [] [] | shared-mime-info | [] [] [] [] [] [] | sharutils | [] [] [] [] [] [] [] [] | shishi | | silky | [] | skencil | [] [] | sketch | [] [] | solfege | [] | soundtracker | [] [] [] | sp | [] | stardict | [] | system-tools-ba... | [] [] [] [] [] [] [] [] | tar | [] [] [] [] [] [] [] | texinfo | [] [] | textutils | [] [] [] [] [] | tin | [] () | tp-robot | [] [] [] [] | tuxpaint | [] [] | unicode-han-tra... | | unicode-transla... | [] [] | util-linux | [] [] [] [] [] [] [] | vorbis-tools | [] [] | wastesedge | () | wdiff | [] [] [] [] [] [] [] [] | wget | [] [] [] [] [] [] [] [] | xchat | [] [] [] [] [] [] [] [] | xkeyboard-config | [] [] [] [] | xpad | [] [] [] | +--------------------------------------------------+ es et eu fa fi fr ga gl gu he hi hr hu id is it 88 22 14 2 40 115 61 14 1 8 1 6 59 31 0 52 ja ko ku ky lg lt lv mk mn ms mt nb ne nl nn no +-------------------------------------------------+ GNUnet | | a2ps | () [] [] () | aegis | () | ant-phone | [] | anubis | [] [] [] | ap-utils | [] | aspell | [] [] | bash | [] | batchelor | [] [] | bfd | | bibshelf | [] | binutils | | bison | [] [] [] | bison-runtime | [] [] [] | bluez-pin | [] [] [] | cflow | | clisp | [] | console-tools | | coreutils | [] | cpio | | cpplib | [] | cryptonit | [] | darkstat | [] [] | dialog | [] [] | diffutils | [] [] [] | doodle | | e2fsprogs | [] | enscript | [] | error | [] | fetchmail | [] [] | fileutils | [] [] | findutils | [] | flex | [] [] | fslint | [] [] | gas | | gawk | [] [] | gbiff | [] | gcal | | gcc | | gettext-examples | [] [] | gettext-runtime | [] [] [] | gettext-tools | [] [] | gimp-print | [] [] | gip | [] [] | gliv | [] | glunarclock | [] [] | gmult | [] [] | gnubiff | | gnucash | () () | gnucash-glossary | [] | gnuedu | | gnulib | [] [] [] [] | gnunet-gtk | | gnutls | | gpe-aerial | [] | gpe-beam | [] | gpe-calendar | [] | gpe-clock | [] [] [] | gpe-conf | [] [] | gpe-contacts | [] | gpe-edit | [] [] [] | gpe-filemanager | [] [] | gpe-go | [] [] [] | gpe-login | [] [] [] | gpe-ownerinfo | [] [] | gpe-package | [] [] | gpe-sketchbook | [] [] | gpe-su | [] [] [] | gpe-taskmanager | [] [] [] [] | gpe-timesheet | [] | gpe-today | [] [] | gpe-todo | [] | gphoto2 | [] [] | gprof | | gpsdrive | () () () | gramadoir | () | grep | [] [] [] [] | gretl | | gsasl | [] | gss | | gst-plugins | [] | gst-plugins-base | | gst-plugins-good | [] | gstreamer | [] | gtick | | gtkam | [] | gtkorphan | [] | gtkspell | [] [] | gutenprint | | hello | [] [] [] [] [] [] | id-utils | [] | impost | | indent | [] [] | iso_3166 | [] | iso_3166_2 | [] | iso_4217 | [] [] [] | iso_639 | [] [] | jpilot | () () () | jtag | | jwhois | [] | kbd | [] | keytouch | [] | keytouch-editor | | keytouch-keyboa... | | latrine | [] | ld | | leafpad | [] [] | libc | [] [] [] [] [] | libexif | | libextractor | | libgpewidget | [] | libgpg-error | | libgphoto2 | [] | libgphoto2_port | [] | libgsasl | [] | libiconv | | libidn | [] [] | lifelines | [] | lilypond | | lingoteach | [] | lynx | [] [] | m4 | [] [] | mailutils | | make | [] [] [] | man-db | () | minicom | [] | mysecretdiary | [] | nano | [] [] [] | nano_1_0 | [] [] [] | opcodes | [] | parted | [] [] | pilot-qof | | psmisc | [] [] [] | pwdutils | | python | | qof | | radius | | recode | [] | rpm | [] [] | screem | [] | scrollkeeper | [] [] [] [] | sed | [] [] | sh-utils | [] [] | shared-mime-info | [] [] [] [] [] | sharutils | [] [] | shishi | | silky | [] | skencil | | sketch | | solfege | | soundtracker | | sp | () | stardict | [] [] | system-tools-ba... | [] [] [] [] | tar | [] [] [] | texinfo | [] [] [] | textutils | [] [] [] | tin | | tp-robot | [] | tuxpaint | [] | unicode-han-tra... | | unicode-transla... | | util-linux | [] [] | vorbis-tools | [] | wastesedge | [] | wdiff | [] [] | wget | [] [] | xchat | [] [] [] [] | xkeyboard-config | [] | xpad | [] [] [] | +-------------------------------------------------+ ja ko ku ky lg lt lv mk mn ms mt nb ne nl nn no 52 24 2 2 1 3 0 2 3 21 0 15 1 97 5 1 nso or pa pl pt pt_BR rm ro ru rw sk sl sq sr sv ta +------------------------------------------------------+ GNUnet | | a2ps | () [] [] [] [] [] [] | aegis | () () | ant-phone | [] [] | anubis | [] [] [] | ap-utils | () | aspell | [] [] | bash | [] [] [] | batchelor | [] [] | bfd | | bibshelf | [] | binutils | [] [] | bison | [] [] [] [] [] | bison-runtime | [] [] [] [] | bluez-pin | [] [] [] [] [] [] [] [] [] | cflow | [] | clisp | [] | console-tools | [] | coreutils | [] [] [] [] | cpio | [] [] [] | cpplib | [] | cryptonit | [] [] | darkstat | [] [] [] [] [] [] | dialog | [] [] [] [] [] [] [] [] [] | diffutils | [] [] [] [] [] [] | doodle | [] [] | e2fsprogs | [] [] | enscript | [] [] [] [] [] | error | [] [] [] [] | fetchmail | [] [] [] | fileutils | [] [] [] [] [] | findutils | [] [] [] [] [] [] | flex | [] [] [] [] [] | fslint | [] [] [] [] | gas | | gawk | [] [] [] [] | gbiff | [] | gcal | [] | gcc | [] | gettext-examples | [] [] [] [] [] [] [] [] | gettext-runtime | [] [] [] [] [] [] [] [] | gettext-tools | [] [] [] [] [] [] [] | gimp-print | [] [] | gip | [] [] [] [] | gliv | [] [] [] [] | glunarclock | [] [] [] [] [] [] | gmult | [] [] [] [] | gnubiff | () | gnucash | () [] | gnucash-glossary | [] [] [] | gnuedu | | gnulib | [] [] [] [] [] | gnunet-gtk | [] | gnutls | [] [] | gpe-aerial | [] [] [] [] [] [] [] | gpe-beam | [] [] [] [] [] [] [] | gpe-calendar | [] | gpe-clock | [] [] [] [] [] [] [] [] | gpe-conf | [] [] [] [] [] [] [] | gpe-contacts | [] [] [] [] [] | gpe-edit | [] [] [] [] [] [] [] [] | gpe-filemanager | [] [] | gpe-go | [] [] [] [] [] [] | gpe-login | [] [] [] [] [] [] [] [] | gpe-ownerinfo | [] [] [] [] [] [] [] [] | gpe-package | [] [] | gpe-sketchbook | [] [] [] [] [] [] [] [] | gpe-su | [] [] [] [] [] [] [] [] | gpe-taskmanager | [] [] [] [] [] [] [] [] | gpe-timesheet | [] [] [] [] [] [] [] [] | gpe-today | [] [] [] [] [] [] [] [] | gpe-todo | [] [] [] [] | gphoto2 | [] [] [] [] [] | gprof | [] [] [] | gpsdrive | [] [] [] | gramadoir | [] [] | grep | [] [] [] [] [] [] [] [] | gretl | [] | gsasl | [] [] [] | gss | [] [] [] | gst-plugins | [] [] [] [] | gst-plugins-base | [] | gst-plugins-good | [] [] [] [] | gstreamer | [] [] [] | gtick | [] | gtkam | [] [] [] [] | gtkorphan | [] | gtkspell | [] [] [] [] [] [] [] [] | gutenprint | [] | hello | [] [] [] [] [] [] [] [] | id-utils | [] [] [] [] | impost | [] | indent | [] [] [] [] [] [] | iso_3166 | [] [] [] [] [] [] | iso_3166_2 | | iso_4217 | [] [] [] [] | iso_639 | [] [] [] [] | jpilot | | jtag | [] | jwhois | [] [] [] [] | kbd | [] [] [] | keytouch | [] | keytouch-editor | [] | keytouch-keyboa... | [] | latrine | [] [] | ld | [] | leafpad | [] [] [] [] [] [] | libc | [] [] [] [] [] | libexif | [] | libextractor | [] [] | libgpewidget | [] [] [] [] [] [] [] | libgpg-error | [] [] | libgphoto2 | [] | libgphoto2_port | [] [] [] | libgsasl | [] [] [] [] | libiconv | [] [] | libidn | [] [] () | lifelines | [] [] | lilypond | | lingoteach | [] | lynx | [] [] [] | m4 | [] [] [] [] [] | mailutils | [] [] [] [] | make | [] [] [] [] | man-db | [] [] | minicom | [] [] [] [] [] | mysecretdiary | [] [] [] [] | nano | [] [] [] | nano_1_0 | [] [] [] [] | opcodes | [] [] | parted | [] | pilot-qof | [] | psmisc | [] [] | pwdutils | [] [] | python | | qof | [] [] | radius | [] [] | recode | [] [] [] [] [] [] [] | rpm | [] [] [] [] | screem | | scrollkeeper | [] [] [] [] [] [] [] | sed | [] [] [] [] [] [] [] [] [] | sh-utils | [] [] [] | shared-mime-info | [] [] [] [] [] | sharutils | [] [] [] [] | shishi | [] | silky | [] | skencil | [] [] [] | sketch | [] [] [] | solfege | [] | soundtracker | [] [] | sp | | stardict | [] [] [] | system-tools-ba... | [] [] [] [] [] [] [] [] [] | tar | [] [] [] [] [] | texinfo | [] [] [] [] | textutils | [] [] [] | tin | () | tp-robot | [] | tuxpaint | [] [] [] [] [] | unicode-han-tra... | | unicode-transla... | | util-linux | [] [] [] [] | vorbis-tools | [] [] | wastesedge | | wdiff | [] [] [] [] [] [] | wget | [] [] [] [] | xchat | [] [] [] [] [] [] [] | xkeyboard-config | [] [] | xpad | [] [] [] | +------------------------------------------------------+ nso or pa pl pt pt_BR rm ro ru rw sk sl sq sr sv ta 0 2 3 58 30 54 5 73 72 4 40 46 11 50 128 2 tg th tk tr uk ven vi wa xh zh_CN zh_HK zh_TW zu +---------------------------------------------------+ GNUnet | [] | 2 a2ps | [] [] [] | 19 aegis | | 0 ant-phone | [] [] | 6 anubis | [] [] [] | 11 ap-utils | () [] | 4 aspell | [] [] [] | 15 bash | [] | 11 batchelor | [] [] | 9 bfd | | 1 bibshelf | [] | 7 binutils | [] [] [] | 9 bison | [] [] [] | 19 bison-runtime | [] [] [] | 15 bluez-pin | [] [] [] [] [] [] | 28 cflow | [] [] | 5 clisp | | 6 console-tools | [] [] | 5 coreutils | [] [] | 16 cpio | [] [] [] | 9 cpplib | [] [] [] [] | 11 cryptonit | | 5 darkstat | [] () () | 15 dialog | [] [] [] [] [] | 30 diffutils | [] [] [] [] | 28 doodle | [] | 6 e2fsprogs | [] [] | 10 enscript | [] [] [] | 16 error | [] [] [] [] | 18 fetchmail | [] [] | 12 fileutils | [] [] [] | 18 findutils | [] [] [] | 17 flex | [] [] | 15 fslint | [] | 9 gas | [] | 3 gawk | [] [] | 15 gbiff | [] | 5 gcal | [] | 5 gcc | [] [] [] | 6 gettext-examples | [] [] [] [] [] [] | 27 gettext-runtime | [] [] [] [] [] [] | 28 gettext-tools | [] [] [] [] [] | 19 gimp-print | [] [] | 12 gip | [] [] | 12 gliv | [] [] | 8 glunarclock | [] [] [] | 15 gmult | [] [] [] [] | 15 gnubiff | [] | 1 gnucash | () | 2 gnucash-glossary | [] [] | 9 gnuedu | [] | 2 gnulib | [] [] [] [] [] | 28 gnunet-gtk | | 1 gnutls | | 2 gpe-aerial | [] [] | 14 gpe-beam | [] [] | 14 gpe-calendar | [] | 3 gpe-clock | [] [] [] [] | 21 gpe-conf | [] [] | 14 gpe-contacts | [] [] | 10 gpe-edit | [] [] [] [] | 20 gpe-filemanager | [] | 6 gpe-go | [] [] | 15 gpe-login | [] [] [] [] [] | 21 gpe-ownerinfo | [] [] [] [] | 21 gpe-package | [] | 6 gpe-sketchbook | [] [] | 16 gpe-su | [] [] [] | 20 gpe-taskmanager | [] [] [] | 20 gpe-timesheet | [] [] [] [] | 18 gpe-today | [] [] [] [] [] | 21 gpe-todo | [] | 7 gphoto2 | [] [] [] [] | 20 gprof | [] [] | 11 gpsdrive | | 4 gramadoir | [] | 7 grep | [] [] [] [] | 34 gretl | | 4 gsasl | [] [] | 8 gss | [] | 5 gst-plugins | [] [] [] | 15 gst-plugins-base | [] [] [] | 9 gst-plugins-good | [] [] [] [] [] | 20 gstreamer | [] [] [] | 17 gtick | [] | 3 gtkam | [] | 13 gtkorphan | [] | 7 gtkspell | [] [] [] [] [] [] | 26 gutenprint | | 3 hello | [] [] [] [] [] | 37 id-utils | [] [] | 14 impost | [] | 4 indent | [] [] [] [] | 25 iso_3166 | [] [] [] [] | 16 iso_3166_2 | | 2 iso_4217 | [] [] | 14 iso_639 | [] | 14 jpilot | [] [] [] [] | 7 jtag | [] | 3 jwhois | [] [] [] | 13 kbd | [] [] | 12 keytouch | [] | 4 keytouch-editor | | 2 keytouch-keyboa... | [] | 3 latrine | [] [] | 8 ld | [] [] [] [] | 8 leafpad | [] [] [] [] | 23 libc | [] [] [] | 23 libexif | [] | 4 libextractor | [] | 5 libgpewidget | [] [] [] | 19 libgpg-error | [] | 4 libgphoto2 | [] | 8 libgphoto2_port | [] [] [] | 11 libgsasl | [] | 8 libiconv | [] | 7 libidn | [] [] | 10 lifelines | | 4 lilypond | | 2 lingoteach | [] | 6 lynx | [] [] [] | 15 m4 | [] [] [] | 18 mailutils | [] | 8 make | [] [] [] | 20 man-db | [] | 6 minicom | [] | 14 mysecretdiary | [] [] | 12 nano | [] [] | 17 nano_1_0 | [] [] [] | 18 opcodes | [] [] | 10 parted | [] [] [] | 10 pilot-qof | [] | 3 psmisc | [] | 10 pwdutils | [] | 3 python | | 0 qof | [] | 4 radius | [] | 6 recode | [] [] [] | 25 rpm | [] [] [] [] | 14 screem | [] | 2 scrollkeeper | [] [] [] [] | 26 sed | [] [] [] | 22 sh-utils | [] | 15 shared-mime-info | [] [] [] [] | 24 sharutils | [] [] [] | 23 shishi | | 1 silky | [] | 4 skencil | [] | 7 sketch | | 6 solfege | | 2 soundtracker | [] [] | 9 sp | [] | 3 stardict | [] [] [] [] | 11 system-tools-ba... | [] [] [] [] [] [] [] | 37 tar | [] [] [] [] | 20 texinfo | [] [] [] | 15 textutils | [] [] [] | 17 tin | | 1 tp-robot | [] [] [] | 10 tuxpaint | [] [] [] | 16 unicode-han-tra... | | 0 unicode-transla... | | 2 util-linux | [] [] [] | 20 vorbis-tools | [] [] | 11 wastesedge | | 1 wdiff | [] [] | 22 wget | [] [] [] | 19 xchat | [] [] [] [] | 29 xkeyboard-config | [] [] [] [] | 11 xpad | [] [] [] | 14 +---------------------------------------------------+ 77 teams tg th tk tr uk ven vi wa xh zh_CN zh_HK zh_TW zu 170 domains 0 1 1 77 39 0 136 10 1 48 5 54 0 2028 Some counters in the preceding matrix are higher than the number of visible blocks let us expect. This is because a few extra PO files are used for implementing regional variants of languages, or language dialects. For a PO file in the matrix above to be effective, the package to which it applies should also have been internationalized and distributed as such by its maintainer. There might be an observable lag between the mere existence a PO file and its wide availability in a distribution. If October 2006 seems to be old, you may fetch a more recent copy of this `ABOUT-NLS' file on most GNU archive sites. The most up-to-date matrix with full percentage details can be found at `http://www.iro.umontreal.ca/contrib/po/HTML/matrix.html'. 1.6 Using `gettext' in new packages =================================== If you are writing a freely available program and want to internationalize it you are welcome to use GNU `gettext' in your package. Of course you have to respect the GNU Library General Public License which covers the use of the GNU `gettext' library. This means in particular that even non-free programs can use `libintl' as a shared library, whereas only free software can use `libintl' as a static library or use modified versions of `libintl'. Once the sources are changed appropriately and the setup can handle the use of `gettext' the only thing missing are the translations. The Free Translation Project is also available for packages which are not developed inside the GNU project. Therefore the information given above applies also for every other Free Software Project. Contact `translation@iro.umontreal.ca' to make the `.pot' files available to the translation teams. partclone-0.2.86/AUTHORS000066400000000000000000000004531262102574200146510ustar00rootroot00000000000000This file is part of partclone package Copyright (C) 2006, 2007 by Steven Shiau (steven _at nchc org tw) 2006~ Thomas Tsai (thomas _at_ nchc org tw) 2006~ Ceasar Sun (ceasar _at_ nchc org tw) 2006~ Jazz Wang (jazz _at_ nchc org tw) 2006~2013 NCHC Free Software Labs, Taiwan. http://www.nchc.org.tw partclone-0.2.86/COPYING000066400000000000000000000430761262102574200146440ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 675 Mass Ave, Cambridge, MA 02139, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS Appendix: How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. partclone-0.2.86/ChangeLog000066400000000000000000003452601262102574200153630ustar00rootroot000000000000002015-11-12 Thomas Tsai release 0.2.86 update README to README.md in all debian/docs release 0.2.86 release 0.2.86 release 0.2.86 add language zh_CN, and ready to release 0.2.86 Merge branch 'release' of github.com:Thomas-Tsai/partclone into release fix fat cluster count 2015-11-09 Thomas Tsai add ` rename README.markdown README.md remove `` 2015-11-09 Peter Dave Hello Create zh_CN.po Update README.markdown Update and rename README to README.markdown Use markdown to be rich text! 2015-11-09 Thomas Tsai update nilfs mount and mkdir Merge branch 'release' of github.com:Thomas-Tsai/partclone into release update README 2015-11-05 Thomas Tsai release 0.2.85 update version to 0.2.85 Merge branch 'release' of github.com:Thomas-Tsai/partclone into release fix fat16 clone issue and add test for fat12, fat16 and fat32 2015-10-13 Thomas Tsai release 0.2.84 update control files update version remove all version test in configure.ac update version.h update release script 2015-10-12 Thomas Tsai set version to 0.2.84 and add nilfs2 test 2015-10-06 Thomas Tsai add test for nilfs 2015-10-05 Thomas Tsai remove .deps add nilfs support 2015-09-24 Thomas Tsai Merge branch 'release' of https://github.com/Thomas-Tsai/partclone into release add xfs 4.2.0 part of source to partclone update release release 0.2.83 fix release fix btrfs 2015-09-23 Thomas Tsai fix btrfs: disk bytenr larger than device size 2015-09-19 Thomas Tsai replace _row_ to _raw_ in all xml files 2015-08-31 Thomas Tsai update debian folder 2015-08-25 Thomas Tsai update release flow 2015-08-24 Thomas Tsai release 0.2.83 xfs: update bitmap calculating time fix 4k and dirty bitmap issue for xfs 2015-08-23 Thomas Tsai update log_mesg 2015-08-20 Thomas Tsai update log message fix 4k and dirty partiiton issue 2015-07-23 Thomas Tsai 0.2.81 2015-07-23 ThomasTsai changs ncurses update 2015-07-21 Thomas Tsai fix calloc error 2015-07-20 Thomas Tsai test vmfs5 and ncursesw set version to 0.2.80 and fix some warnnings 2015-07-17 Thomas Tsai update vmfs5 and test double free issue Merge branch 'release' of https://github.com/Thomas-Tsai/partclone into release try to fix double free issus 2015-07-01 Thomas Tsai fix rules ready to release 0.2.79 patch from DimStar77 and fix missing includes fix vmfs 2015-06-30 Thomas Tsai try to fix vmfs5 2015-05-15 Thomas Tsai Merge branch 'release' of github.com:Thomas-Tsai/partclone into release accept patch from Georges to fix a bug report from Debian, about missed builds for 2015-04-09 Thomas Tsai ready to release 0.2.78 set version to 0.2.78 fix 16T partition issue 2015-04-02 Thomas Tsai fix hiuge filesystem issue 2015-03-25 Thomas Tsai update ChangeLog and version.h release 0.2.77 remove some check that is duplicate and made error. 2015-01-21 Thomas Tsai fix char related issue for bad sectors by Chris Clayton Conflicts: docs/partclone.imager.8 src/partclone.c src/version.h 2015-01-16 Thomas Tsai fix xfs and release(0.2.76) to test * fix xfs clone issue while set size to backup but bigger then device size and not stop 2014-12-30 Thomas Tsai release 0.2.75 2014-12-29 Thomas Tsai merge 0.2.74 test btrfs add source of btrfs update source of btrfs try to fix btrfs 2014-11-05 Thomas Tsai hide note: without note option update version script add --note option to fix issue #56 add fail-mbr/Makefile.am to pass prefix to new makefile which note from Fisiu (https://github.com/Thomas-Tsai/partclone/commit/cc5b6545bccd60f567d49944d7d9c36e0f4fc74b#commitcomment-8413428) fix issue #57 and use PKG_CHECK_MODULES to check version 2014-09-04 Thomas Tsai test about exfat and f2fs 2014-09-03 Thomas Tsai upgrade exfat to 1.1.0 2014-09-02 Thomas Tsai initial f2fs support 2014-08-28 Thomas Tsai update control 2014-07-15 Thomas Tsai update version to 0.2.72 2014-07-09 Thomas Tsai add package for debian jessie add package for debian wheezy 2014-07-08 Thomas Tsai fix configure.ac and add libblkid-dev check 2014-07-07 Thomas Tsai fix xfs 2014-05-14 Thomas Tsai 0.2.71 ready to release merger btrfs to 3.14 and update makefile 2014-05-13 Thomas Tsai try to merge btrfs 3.14.1 2014-01-20 Thomas Tsai release 0.2.70 update version to 0.2.70 fix restore-to-raw option 2013-12-26 Thomas Tsai update log, po and version ready to release 0.2.69 2013-12-25 Thomas Tsai finish tests script 2013-12-23 Thomas Tsai merge tests/info.test fix segfault for info.c 2013-12-18 Thomas Tsai add pre stable test 2013-12-12 Thomas Tsai add test for reiser4 fix reiser4 status issue 2013-12-11 Thomas Tsai add quiet test add translation for Vietnamese from Trần Ngá»c Quân vnwildman@gmail.com 2013-12-09 Thomas Tsai 0.2.68 autoreconf done add stdin for partclone.info 2013-12-03 Thomas Tsai update rule for clonezilla fix xfs static link issue 2013-12-02 Thomas Tsai fix error: #error You should define _FILE_OFFSET_BITS=64 accept patch from daniel Rozenberg. While checking the man file I noticed some typos, fixed here update version and log fix makefile for archlinux 2013-07-09 Thomas Tsai * add test btrfs version to configure * upgrade btfs to 0.20rc1 * update configure for automake 1.13 update dd mode string 2013-07-03 Thomas Tsai 0.2.66 fix read stdin size smaller than buffer size for partclone.dd 2013-07-02 Thomas Tsai 0.2.65 update open error for ddd 2013-07-01 Thomas Tsai update dd_bs to 1024 0.2.64 update ignore dix dd issue 2013-06-30 Thomas Tsai update version and update manual for partclone.dd and partclone.imager add imager and fix dd 2013-06-18 Thomas Tsai add version.h update git version 0.2.62 fix unused variable fix used_block error 2013-06-13 Tran Ngoc Quan Init Vietnamese translation 2013-06-09 Thomas Tsai Merge pull request #35 from pfrouleau/optimize_crc32_computation Optimize crc32 computation Merge pull request #34 from pfrouleau/ignore_version_h Add src/version.h to .gitignore since it is a generated file Merge pull request #33 from pfrouleau/fix_version_h_generation teach toolbox to use a relative path to generate src/version.h 2013-06-07 Patryck Rouleau teach toolbox to use a relative path to generate src/version.h When toolbox is called from the makefile, src/ is the working directory and it fails to create src/version.h. By using a path relative to its own location, it can be called from anywhere in the project. Add src/version.h to .gitignore since it is a generated file Optimize crc32 computation Move the crc table initialization outside of the loop to avoid to check the init flag for every byte. My benchmark show a gain of 26% to clone a partition of 17G with 10G used: init crc32 table inside the loop: real 4m23.649s user 2m20.301s sys 1m34.782s init crc32 table outside the loop: real 3m13.169s user 1m15.269s sys 1m30.966s 2013-06-06 Thomas Tsai update test script 2013-06-04 Thomas Tsai add options to partclone.info to assign logfile path 2013-05-26 Thomas Tsai typo of partclone manual 2013-05-20 Thomas Tsai 0.2.61 2013-05-06 Thomas Tsai find a lot of warning from -Wall and fix it. change default buffer size to 1M 2013-05-03 Thomas Tsai add ncurses display for chkimg. add option to assign buffer size update usage of partclone.restore 2013-04-29 Thomas Tsai accept patch from Роман Шишнев to fix: 1. cpu usage, partclone uses too much cpu. The main problem is too short buffer (fs block size) for almost all io operations. To increase buffer size I had to rewrite most part of main.c. 2. duplicate code, duplicated bugs. after patch which contains all my changes for partclone, Now the cpu usage is the only crc-checksumming. 2013-03-29 Thomas Tsai accept patch from Jumpei Ogawa to fix memory leak. this issue also fixed to btrfs git http://git.kernel.org/cgit/linux/kernel/git/mason/btrfs-progs.git/commit/?id=1cce8d72f2d0d00bd5c9322b16176de0fb56aff6 update test exfat 2013-03-28 Thomas Tsai ignore check failmbr ready to release 0.2.60 update rules for squeeze 2013-02-21 Thomas Tsai 0.2.59 2013-02-20 Thomas Tsai add count_used_block update git ignore fix minix version 3 2013-02-06 Thomas Tsai fix minix clone error 2013-02-05 Thomas Tsai initial minix clone 2013-01-30 Thomas Tsai add option w, --skip_write_error to skip block write erro and keep restoring data 2013-01-22 Thomas Tsai fix path of fallmbr 0.2.58 2013-01-21 Thomas Tsai update small screen issue 2013-01-18 Thomas Tsai add test file try to fix terminal size issue 2013-01-14 Thomas Tsai package failmbr update makefile for fail-mbr 0.2.57 update jfs 2013-01-10 Thomas Tsai fix jfs clone issue 2013-01-02 Thomas Tsai update todo Merge branch 'master' into free Conflicts: TODO update ufs 2012-11-19 Thomas Tsai Merge pull request #28 from okkez/add-missing-declarations Add missing declarations. Merge pull request #27 from okkez/suppress-warnings-by-gcc-xfs Suppress warnings reported by gcc for xfsclone.[ch] Merge pull request #26 from okkez/suppress-warnings-by-gcc-vmfs Suppress warnings reported by gcc for vmfsclone.[ch] and vmfs5clone.c Merge pull request #25 from okkez/suppress-warnings-by-gcc-extfs Suppress warnings reported by gcc for extfsclone.[ch] Merge pull request #24 from okkez/suppress-warnings-by-gcc-fat Suppress warnings reported by gcc for fatclone.[ch] Merge pull request #23 from okkez/cleanup-common Suppress warnings reported by gcc for main.c, partclone.c, progress.h Merge pull request #22 from okkez/cleanup-restore Remove unused variables in restore.c Merge pull request #21 from okkez/cleanup-chkimg Remove unused variables in chkimg.c. Merge pull request #20 from okkez/suppress-warnings-by-gcc-exfat Suppress warnings reported by gcc for exfatclone.[ch] Merge pull request #19 from okkez/suppress-warnings-by-gcc-btrfs Suppress warnings reported by gcc for btrfsclone.h. Merge pull request #18 from okkez/fix-ufs-problems Fix ufs problems 2012-11-17 Thomas Tsai Merge pull request #17 from okkez/fix-jfs-problems Fix jfs problems Merge pull request #16 from okkez/fix-format-string-for-reiser4 Fix format string for reiser4clone.c Merge pull request #15 from okkez/suppress-warnings-by-gcc-reiser4 Suppress warnings reported by gcc for reiser4clone.h Merge pull request #14 from okkez/suppress-warnings-by-gcc-reiserfs Suppress warnings reported by gcc for reiserfsclone.[ch] Merge pull request #13 from okkez/suppress-warnings-by-gcc-hfsp Suppress warnings by gcc for hfspclone.[ch] Merge pull request #12 from moriyama/fix-calling-vmfs_fs_open Fix calling vmfs_fs_open() Merge pull request #11 from okkez/cleanup-ddclone Cleanup ddclone Merge pull request #10 from okkez/add-default-cflags Add default CFLAGS Merge pull request #8 from okkez/use-vsnprintf Use vsnprintf() instead of vsprintf() in src/partclone.c Merge pull request #7 from okkez/fix-infinite-loop Avoid infinite loop in src/main.c Merge pull request #6 from okkez/plug-a-memory-leak Plug a memory leak in src/partclone.c 2012-11-14 Kenji Okimoto Add missing declarations. main.c:314: warning: implicit declaration of function 'get_image_bitmap' main.c:642: warning: implicit declaration of function 'write_last_block' Remove an unused variable. xfsclone.c:180: warning: unused variable 's_pos' Do not declare static functions in header file. xfsclone.h:40: warning: 'set_bitmap' declared 'static' but never defined xfsclone.h:43: warning: 'fs_open' declared 'static' but never defined xfsclone.h:46: warning: 'fs_close' declared 'static' but never defined 2012-11-13 Kenji Okimoto Suppress warnings reported by gcc vmfs5clone.c:235: warning: control reaches end of non-void function vmfs5clone.c:194: warning: control reaches end of non-void function Add missing include to suppress a warning vmfs5clone.c:405: warning: implicit declaration of function 'sleep' Suppress warnings reported by gcc. vmfs5clone.c:268: warning: unused variable 'next' vmfs5clone.c:265: warning: unused variable 'lvm' vmfs5clone.c:315: warning: unused variable 'status' vmfs5clone.c:314: warning: unused variable 'total' vmfs5clone.c:313: warning: unused variable 'prog_total' Suppress warnings reported by gcc vmfsclone.c:33: warning: unused variable 'next' vmfsclone.c:30: warning: unused variable 'lvm' Do not declare static functions in header file. vmfsclone.h:15: warning: 'fs_open' declared 'static' but never defined vmfsclone.h:18: warning: 'fs_close' declared 'static' but never defined Use blk_t instead of int to suppress a warning. extfsclone.c: In function ‘device_size’: extfsclone.c:87:5: warning: pointer targets in passing argument 3 of ‘ext2fs_get_device_size’ differ in signedness [-Wpointer-sign] In file included from extfsclone.c:17:0: /usr/include/ext2fs/ext2fs.h:1196:18: note: expected ‘blk_t *’ but argument is of type ‘int *’ Add missing braces to suppress a warning extfsclone.c:193:8: warning: suggest explicit braces to avoid ambiguous ‘else’ [-Wparentheses] Do not declare static functions in header file. extfsclone.h:15:13: warning: ‘fs_open’ declared ‘static’ but never defined [-Wunused-function] extfsclone.h:18:13: warning: ‘fs_close’ declared ‘static’ but never defined [-Wunused-function] extfsclone.h:21:12: warning: ‘block_size’ declared ‘static’ but never defined [-Wunused-function] extfsclone.h:24:27: warning: ‘device_size’ declared ‘static’ but never defined [-Wunused-function] extfsclone.h:27:27: warning: ‘block_count’ declared ‘static’ but never defined [-Wunused-function] extfsclone.h:30:27: warning: ‘get_used_blocks’ declared ‘static’ but never defined [-Wunused-function] extfsclone.h:36:12: warning: ‘test_extfs_type’ declared ‘static’ but never defined [-Wunused-function] Add prototype declaration Rename variable name j -> i Remove unused variables in fatclone.c fatclone.c:246:24: warning: unused variable ‘i’ [-Wunused-variable] fatclone.c:274:24: warning: unused variable ‘i’ [-Wunused-variable] fatclone.c:301:24: warning: unused variable ‘i’ [-Wunused-variable] fatclone.c:332:24: warning: unused variable ‘free_blocks’ [-Wunused-variable] fatclone.c:331:24: warning: unused variable ‘cluster_count’ [-Wunused-variable] fatclone.c:330:24: warning: unused variable ‘sec_per_fat’ [-Wunused-variable] fatclone.c:329:24: warning: unused variable ‘data_sec’ [-Wunused-variable] fatclone.c:326:10: warning: unused variable ‘sig’ [-Wunused-variable] fatclone.c:370:20: warning: unused variable ‘opt’ [-Wunused-variable] fatclone.c:369:14: warning: unused variable ‘Fat32_Entry’ [-Wunused-variable] fatclone.c:368:14: warning: unused variable ‘Fat16_Entry’ [-Wunused-variable] fatclone.c:362:9: warning: unused variable ‘rd’ [-Wunused-variable] fatclone.c:361:31: warning: unused variable ‘j’ [-Wunused-variable] fatclone.c:431:9: warning: unused variable ‘rd’ [-Wunused-variable] Do not declare static functions in header file. fatclone.h:89:13: warning: ‘fs_open’ declared ‘static’ but never defined [-Wunused-function] fatclone.h:92:13: warning: ‘fs_close’ declared ‘static’ but never defined [-Wunused-function] fatclone.h:101:27: warning: ‘get_used_block’ declared ‘static’ but never defined [-Wunused-function] fatclone.h:104:14: warning: ‘get_fat_type’ declared ‘static’ but never defined [-Wunused-function] fatclone.h:122:27: warning: ‘mark_reserved_sectors’ declared ‘static’ but never defined [-Wunused-function] Remove an unused variable partclone.c:348:20: warning: unused variable ‘opt’ [-Wunused-variable] This warning is displayed if specified "--enable-ncursesw". Remove unused variables in main.c main.c:130:11: warning: unused variable ‘s_count’ [-Wunused-variable] main.c:128:11: warning: unused variable ‘n_crc_size’ [-Wunused-variable] Do not declare static functions in header file. progress.h:53:13: warning: ‘calculate_speed’ declared ‘static’ but never defined [-Wunused-function] progress.h:63:8: warning: ‘open_p_ncurses’ declared ‘static’ but never defined [-Wunused-function] progress.h:64:8: warning: ‘close_p_ncurses’ declared ‘static’ but never defined [-Wunused-function] Remove unused variables in partclone.c partclone.c:1056:24: warning: unused variable ‘dev_size’ [-Wunused-variable] partclone.c:1126:9: warning: unused variable ‘block’ [-Wunused-variable] Suppress a warning reported by gcc. partclone.c:343:9: warning: unused variable ‘debug’ [-Wunused-variable] This warning is displayed if specify "--enable-ncursesw". Remove unused variables in restore.c restore.c:80:11: warning: unused variable ‘s_count’ [-Wunused-variable] restore.c:75:19: warning: unused variable ‘crc’ [-Wunused-variable] restore.c:68:24: warning: unused variable ‘needed_size’ [-Wunused-variable] Remove unused variables in chkimg.c. chkimg.c:187:11: warning: unused variable ‘image_hdr_magic’ [-Wunused-variable] chkimg.c:185:11: warning: unused variable ‘raw’ [-Wunused-variable] chkimg.c:182:11: warning: unused variable ‘rescue_num’ [-Wunused-variable] chkimg.c:181:11: warning: unused variable ‘s_count’ [-Wunused-variable] chkimg.c:162:12: warning: unused variable ‘source’ [-Wunused-variable] Remove unused variables. ddclone.c:77:9: warning: variable ‘pres’ set but not used [-Wunused-but-set-variable] ddclone.c:71:11: warning: unused variable ‘s_count’ [-Wunused-variable] ddclone.c:68:11: warning: unused variable ‘cmp’ [-Wunused-variable] ddclone.c:67:11: warning: unused variable ‘bitmagic_r’ [-Wunused-variable] ddclone.c:66:11: warning: unused variable ‘bitmagic’ [-Wunused-variable] ddclone.c:61:24: warning: unused variable ‘sf’ [-Wunused-variable] ddclone.c:61:12: warning: unused variable ‘offset’ [-Wunused-variable] Remove unused variables. exfatclone.c:53: warning: unused variable 'free_clusters' exfatclone.c:53: warning: unused variable 'free_sectors' exfatclone.c:52: warning: unused variable 'sb' Suppress warnings reported by gcc. exfatclone.h:15: warning: 'fs_open' declared 'static' but never defined exfatclone.h:18: warning: 'fs_close' declared 'static' but never defined 2012-11-12 Kenji Okimoto Suppress warnings reported by gcc. btrfsclone.h:15: warning: 'fs_open' declared 'static' but never defined btrfsclone.h:18: warning: 'fs_close' declared 'static' but never defined Remove unused variables reported by cppcheck. [src/jfsclone.c:126]: (style) Unused variable: btotal [src/jfsclone.c:126]: (style) Unused variable: bfree [src/jfsclone.c:299]: (style) Variable 'lblock' is assigned a value that is never used [src/jfsclone.c:305]: (style) Unused variable: dmap_l2bpp [src/jfsclone.c:306]: (style) Unused variable: d_address [src/jfsclone.c:307]: (style) Unused variable: d_map [src/jfsclone.c:308]: (style) Unused variable: dmap [src/jfsclone.c:308]: (style) Unused variable: l0 [src/jfsclone.c:308]: (style) Unused variable: l1 [src/jfsclone.c:309]: (style) Variable 'next' is assigned a value that is never used [src/jfsclone.c:310]: (style) Unused variable: btotal [src/jfsclone.c:310]: (style) Unused variable: bfree [src/jfsclone.c:311]: (style) Unused variable: tub [src/jfsclone.c:312]: (style) Variable 'tb' is assigned a value that is never used [src/jfsclone.c:313]: (style) Variable 'pb' is assigned a value that is never used [src/jfsclone.c:314]: (style) Variable 'block_used' is assigned a value that is never used [src/jfsclone.c:315]: (style) Variable 'block_free' is assigned a value that is never used Do not declare static functions in header file. This fix suppresses GCC warnings. Remove unused variables reported by cppcheck. [src/ufsclone.c:184]: (style) Variable 'start' is assigned a value that is never used [src/ufsclone.c:184]: (style) Variable 'bit_size' is assigned a value that is never used Initialize `fsflags` and update it correctly. Before apply this patch, sometimes this program can crash. Do not declare static functions in header file. This fix suppresses GCC warnings. Use "%llu" instead of "%lli". Because `block` and `bfree` are unsigned long long. Fix arguments order Suppress warnings reported by gcc reiser4clone.h:15:13: warning: ‘fs_open’ declared ‘static’ but never defined [-Wunused-function] reiser4clone.h:18:13: warning: ‘fs_close’ declared ‘static’ but never defined [-Wunused-function] Remove an unused variable. reiserfsclone.c:71: warning: unused variable 'node' Suppress warnings reported by gcc reiserfsclone.h:15: warning: 'fs_open' declared 'static' but never defined reiserfsclone.h:18: warning: 'fs_close' declared 'static' but never defined 2012-11-08 Masayuki Moriyama fstype.c: fix incompatible pointer types warning vmfs5clone.c: fix incompatible pointer types warning vmfsclone.c: fix incompatible pointer types warning 2012-11-08 Kenji Okimoto Remove an unused variable reported by gcc hfsplusclone.c:129: warning: unused variable 'i' Suppress warnings reported by gcc. hfsplusclone.h:69: warning: 'reverseShort' declared 'static' but never defined hfsplusclone.h:71: warning: 'reverseInt' declared 'static' but never defined hfsplusclone.h:73: warning: 'IsAllocationBlockUsed' declared 'static' but never defined hfsplusclone.h:75: warning: 'print_fork_data' declared 'static' but never defined hfsplusclone.h:78: warning: 'fs_open' declared 'static' but never defined hfsplusclone.h:81: warning: 'fs_close' declared 'static' but never defined 2012-11-07 Kenji Okimoto Add default CFLAGS Remove needless cast Use "%llu" instead of "%lli" because total_write is unsigned long long 2012-11-06 Kenji Okimoto Use vsnprintf() instead of vsprintf(). This may avoid buffer overflow 2012-11-06 Thomas Tsai add check to fail-mbr add fail-mbr fix error: ‘debug’ undeclared again fix error: ‘debug’ undeclared 2012-11-06 Kenji Okimoto Plug a memory leak Use unsigned long long instead of int image_hdr.totalblock may be unsigned 64 bits in size. 2012-11-06 Thomas Tsai Merge pull request #4 from okkez/malloc-check Add malloc/calloc result check Merge pull request #3 from okkez/fix-problems-reported-by-cppcheck Fix problems reported by cppcheck 2012-11-06 Thomas Tsai Revert "remove exfat temporarily" This reverts commit cda497b0bc6f6dda2777e1eacd45841b5766a35b. Merge branch 'master' of ssh://free.nchc.org.tw:3322/home/gitpool/partclone Revert "add test script for offset" rollback exfat This reverts commit ca18098bebb3585545e62a62bb651c3d0534891c. try to branch exfat release 0.2.56 remove exfat temporarily 2012-11-02 Kenji Okimoto Add check calloc() result Add check calloc() result Exit if calloc() failed Add check malloc() result Add check malloc() result Add check malloc() result ensure NULL terminated string do not free NULL plug a memory leak fix buffer overflow 2012-10-22 Thomas Tsai add test script for offset add offset function 2012-10-11 Thomas Tsai update TODO update configure release 0.2.55 2012-10-08 Thomas Tsai fix bug from sourceforge track system: some files restored by partclone.vmfs3 is corrupted incorrect information in the log accept patch files: partclone-0.2.54-fix-printf-format-1.patch from Masayuki Moriyama partclone-fix-wrong-bitmap-of-vmfsclone.patch from Masayuki Moriyama Masayuki Moriyama report two bugs and patchs, Thank You. 2012-10-01 Thomas Tsai update TODO 2012-09-26 Thomas Tsai * upgrade btrfs version (still 0.19 accept patches from debian source) * add --enable-fs-test to run file system clone/restore test suite * add dd test as default test * versioin 0.2.54 update test script 2012-09-25 Thomas Tsai update tests comment some test add tests add make check but not work well set version 0.2.53 2012-09-24 Thomas Tsai add debian.squeeze back and rename debian to debian.sid 2012-09-21 Thomas Tsai update makefile add more man pages update man page add man page remove sid squeeze update debian folder 2012-09-20 Thomas Tsai update ncurses interface. fix issue: ncurses interface can't work on saving partition with pipe because both use stdout at the same time. since initscr() use stdout default, and we try to replace with newterm() with stderr. set ncurses window to stderr modified: src/Makefile.in modified: src/ddclone.c modified: src/main.c modified: src/partclone.c modified: src/restore.c 2012-09-17 Thomas Tsai update TODO 2012-07-31 Thomas Tsai update some docs 2012-07-30 Thomas Tsai update version to 0.2.51 update process for elapsed time over 24hr 2012-07-25 Thomas Tsai update supported list 2012-07-13 Thomas Tsai update makefile 2012-07-10 Thomas Tsai version 0.2.50 update test and size information add test for exfat update exfat and add exfat man docs add exfat 2012-06-27 Thomas Tsai add more detail message in image head output 2012-06-15 Thomas Tsai add partclone.btrfs.8 update control update control fix quiet mode issue. The issue make partclone can't stop/finish even action is done. bug report from pille 2012-05-30 Thomas Tsai update manpage 2012-05-29 Thomas Tsai update docs update docs 2012-05-18 Thomas Tsai minor update readme 2012-05-16 Thomas Tsai update TODO 2012-05-01 Thomas Tsai Merge branch 'master' of partclone.nchc.org.tw:/home/partclone update vmfs for some unallocated block 2012-04-29 Thomas Tsai A partclone bug found when it backs up WindowsServer2008R2 (64bit) on 2012-04-26 Thomas Tsai update bitmap progress 2012-04-26 thomas ignore unallocated block for vmfs 2012-04-19 Thomas Tsai update control for vmfs 2012-04-18 Thomas Tsai 0.2.47 update fresh done update fresh, add sleep in progress thread to reduce cpu usage, contributed and bug information from http://sourceforge.net/tracker/?func=detail&aid=3509757&group_id=115473&atid=671650 2012-04-12 Thomas Tsai change row to raw, noticed from Vincent van Adrighem try to fix ID: 3509757 from clonezilla track system 2012-04-01 Thomas Tsai update vmfs5 2012-03-29 Thomas Tsai remove vmfs5clone.c 2012-03-28 Thomas Tsai update for vmfs-tool 0.2.5 come back Merge branch 'master' of partclone.nchc.org.tw:/home/partclone update for vmfs-tool 0.2.5 Merge branch 'fixcrc' remove new crc and accept vmfs5 update for vmfs-tool 0.2.5 2012-03-27 Thomas Tsai crc32 2012-02-17 Matthew Booth Make crc32() explicitly 32 bit Remove redundant copy of crc_buffer Allocate crc_buffer on the stack Avoid repeated malloc/free of a 4 byte buffer by allocating crc_buffer on the stack. Make constant string static const *const Minor log message cleanup 2012-02-11 Thomas Tsai add partclone.vmfs5 ignored update vmfs5 2012-02-09 Thomas Tsai add vmfs5clone.c to clone vmfs5 update vmfs5 update makefile to create partclone.vmfs5 2012-02-08 Thomas Tsai 0.2.46 * accept patch from Rommer to update memory usage * update document, some example error. * update vmfsclone to backup vmfs5 well 2012-01-28 Thomas Tsai merge update manpages 2012-01-18 Thomas Tsai add compatibility of vmfs3 and vmfs5 2012-01-17 Thomas Tsai print vmfs version from fstype update pui for mode dev-yo-dev 2012-01-05 Thomas Tsai update for vmfs 2011-12-27 Thomas Tsai 0.2.43 add option B to disable block detail 0.2.42 add finish progress to dd 0.2.41 add thread to dd, restore and chkimg 2011-12-26 Thomas Tsai add thread to display progress, draft update progress bar 2011-12-23 Thomas Tsai add block status update progress seeking at 100% 2011-12-12 Thomas Tsai update version to "1.0" at ntfsfixboot.c line 218 0.2.39 update ntfsfixboot.c to version 1.0 2011-11-25 Thomas Tsai 0.2.38 update for progress 2011-11-23 Thomas Tsai update for makefile for ncursesw release 0.2.37 add -I/usr/include/ncursesw/ 2011-11-09 Thomas Tsai 0.2.36 update ncurses size 2011-11-02 Thomas Tsai update toolbox update toolbox update toolbox update toolbox update 2011-11-01 Thomas Tsai move partclone.spec to README.Packages/partclone.spec remove debian add debian update TODO re remove debian add debian update version script save last changelog ($version) update control for debian-sid move debian folder to README.Packages as sample 2011-10-31 Thomas Tsai update autoconf and automake for squeeze 2011-10-27 Thomas Tsai update script folder done update debain/control re release 0.2.33 update test script 2011-10-27 root update memory mangment update memory managment 2011-10-26 root update ncurses 2011-10-26 Thomas Tsai test ncurses progress bar 2011-10-25 Thomas Tsai update 0.2.33 2011-10-19 Thomas Tsai release 0.2.32 update test script add bitmap.h 2011-10-18 Thomas Tsai accept patch from Rommer 2011-10-12 Thomas Tsai release 0.2.31 2011-10-13 Thomas Tsai update for vmfs5 2011-10-11 Thomas Tsai patch vmfs and release patch for new vmfs library 2011-09-14 Thomas Tsai performance issue from Randy Syring "I came across something you may want to update: in get_image_bitmap() you loop through the blocks and increment bused and bfree. However, those values are only used if debug >= 2. Seems like that loop could be moved inside the if statement just below it." 2011-09-12 Thomas Tsai release 0.2.29 2011-09-10 Thomas Tsai release 0.2.29 2011-09-09 Thomas Tsai make e2fs compact for squeeze 2011-09-05 Thomas Tsai update configure update ncurses for sid 2011-08-30 Thomas Tsai fix bug for reiserfs 0.2.27 0.2.27 accept suggestion from Paul, many thanks Merge branch 'master' of partclone.nchc.org.tw:/home/partclone accept patches from Georges - 10-configure.ac.patch removes a flag '-static' in a compilation - 20-manpages fixes a few typos in manpages (s/sp1/sp 1/) - 30-fixIntTypes fixes a more subtle bug, it make the definition of integer types more precise and architecture-agnostic. See http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=636927 2011-08-18 Thomas Tsai try to release dbg version update test script release 0.2.26 stable update help description update test script 2011-08-17 Thomas Tsai add dbg package script can do basic test for developer initial extra test script 2011-08-14 Thomas Tsai Merge branch 'master' of ssh://partclone.nchc.org.tw/home/partclone 2011-08-15 Thomas Tsai release version 0.2.25 update for e2fslibs 1.42~WIP-2011-07-02 2011-08-14 Thomas Tsai release version 0.2.25 update configure.ac for new e2fslibrary 2011-08-01 Thomas Tsai compact ntfs and ntfs-3g 2011-07-28 Thomas Tsai add ntfs-3g library support for ntfs accept patch from Arkadiusz Patyk because In PLD Linux now we switch from ntfsprog to ntfs-3g. update patch and try to keep ntfsprogs. 2011-05-24 Thomas Tsai release 0.2.4 with deb file * accept patch from Ian Abbott. * Ian Abbott realized it would be quicker if it only copied the in-use areas of the partition. ddrescue has a '--domain-log=FILE' option which can be used to restrict it to certain areas, so the problem is to create such a domain log file to cover the areas used by the filesystem on the partition. ... check mail list to get more details... 2011-05-14 Thomas Tsai Merge branch '0.2.8-update' of partclone.nchc.org.tw:/home/partclone into 0.2.8-update add docbook style manpages : partclone.xxx.xml 2011-04-28 Thomas Tsai update test script add chkimg test add test 2011-04-22 Thomas Tsai lost xxxfs.8 add template man page for all file system update marco so release 0.2.23 for better manpages 2011-04-13 Thomas Tsai update gitignore update manual as link update manual update man 2011-03-28 Thomas Tsai 0.2.22 release typo error for progress 2011-03-22 Thomas Tsai release version 0.2.21 fix bug for partclone.dd 2011-03-21 Thomas Tsai Merge branch '0.2.8-update' of partclone.nchc.org.tw:/home/partclone into 0.2.8-update fix bug for partclone.dd 2011-03-17 Thomas Tsai release 0.2.20 2011-03-14 Thomas Tsai fix partclone.dd / partclone.restore hard to show right message for stdin data. We use target size as source size for the special case. 2011-03-09 Thomas Tsai 0.2.19: fixbug: progress fail when just 10 block restore release 0.2.19 update makefile for btrfs 2011-02-18 Thomas Tsai * add option max_block_cache to get better performance escpcially small block size(fat) * update typo error * Version 0.2.18 2011-01-25 Thomas Tsai update ChangeLog fix ufs error update ext4 mismatch and new release version 2011-01-18 Thomas Tsai fix commit: replace reiserfs with ntfs, thanks for Marcos Felipe Rasia de Mello 2011-01-13 Thomas Tsai fix bug for ufs unclean 2010-11-02 Thomas Tsai update POs 2010-11-01 Thomas Tsai Fix configure.ac and makefile.am and accept patchs from Cedric OLLIVIER ollivier.cedric _at_ gmail.com. 2010-10-06 Thomas Tsai update version 0.2.16 * add option --quiet to disable progress bar * add option --restoew_row_file to restore to special row file for loop device 2010-09-01 Thomas Tsai fix btrfs bug fix btrfs clone lost update some files update version and add fr_FR locale 2010-08-31 Thomas Tsai Bug fixed: btrfs clone fail, lost some metadata message 2010-08-22 Thomas Tsai update changelog update version release test version remove other btfs files add btrfs support 2010-07-28 Thomas Tsai fix buf for jfsclone autoreconf * add link partclone.VMFS_volume_member * fix bug: jfsclone segfault * add debian/control pkg-config 2010-07-01 Thomas Tsai fix bug of jfsclone fix jfs: set unknown status bock as used fix bug for jfs_logform 2010-06-30 Thomas Tsai update changelog update makefile.am for jfs remove jfs_devices.h jfs_devices.c update version to 0.2.12 add libjfs to control file and get libjfs...deb from partclone.nchc.org.tw/download/misc/ 2010-06-29 Thomas Tsai add support for jfs 2010-06-09 Thomas Tsai update debian/changlog update to 0.2.11 add Build-Depends libvmfs fix xfsclone.c: conflicting types for ‘set_bitmap’ 2010-05-19 Thomas Tsai release testing 0.2.10 remove one not necessary message release 0.2.10 for xfsclone 2010-05-15 thomas * update xfsclone.c 2010-05-11 thomas * try to merge from new xfs clone * replace memcpy to strncpy to avoid accessing memory beyond string terminator * and patch from Andre Przywara , many thanks. fix bug about chkimg fail 2010-04-29 thomas * release 0.2.9 fix bug: alloc double memory for bitmap when restore. fix bug: bitmap error for over 8.7T partition backup and restore. 2010-04-23 thomas fix xfsclone error 2010-04-12 Thomas Tsai initial new xfsclone 2010-04-01 Thomas Tsai fix about: extfsclone do fs_check and report error message when mounted times larger than fs default, but error message lost report mounted times. 2010-03-29 Thomas Tsai update version to 0.2.8 * make progress bar update faster * fix progress to make calculating bitmap takes faster 2010-03-16 Thomas Tsai add git ignore files and fix toolbox to create right git commit hash update progress bar 2010-03-15 Thomas Tsai * update version to 0.2.6 * try to fix progress rate * also change to partclone.c to fix print_readable_size modified: src/partclone.c modified: src/progress.c 2010-03-12 Thomas Tsai update size number show partition size more cleanly Merge branch 'master' of partclone.nchc.org.tw:/home/partclone 2010-03-12 thomas * fix rate = 0, hide the size for bitmap only. * print readable size * update version * update changelog 2010-03-11 thomas * fix rate = 0, hide the size for bitmap only. * print readable size * update version 2010-03-10 Thomas Tsai update deb changelog set version to 0.2.4 add export version 2010-03-10 thomas add git revision by attribute update process inf error new file: .gitattributes modified: src/progress.c modified: src/version.h 2010-03-02 Thomas Tsai add -v option to display VERSION and git version remove unnecessary code 2010-03-01 thomas try to build package via git build package modified: ChangeLog modified: debian/changelog modified: po/partclone.pot modified: po/zh_TW.gmo modified: po/zh_TW.po modified: toolbox git-svn-id: svn+ssh://140.110.240.196/partclone_svn@363 93b75dfe-da2d-4241-a08d-2141769abc04 ~ update message of fstype ~ replace to git repository ~ update version display ~ add gitlog-to-changelog to convert git log to ChangeLog On branch master Changes to be committed: new file: gitlog-to-changelog modified: ChangeLog modified: configure modified: configure.ac modified: src/chkimg.c modified: src/fstype.c modified: src/partclone.c modified: src/version.h modified: toolbox git-svn-id: svn+ssh://140.110.240.196/partclone_svn@362 93b75dfe-da2d-4241-a08d-2141769abc04 update version number modified: Makefile.am modified: Makefile.in modified: configure modified: configure.ac modified: src/Makefile.am modified: src/Makefile.in modified: src/version.h git-svn-id: svn+ssh://140.110.240.196/partclone_svn@361 93b75dfe-da2d-4241-a08d-2141769abc04 2010-02-24 thomas * add fstype.c to test vmfs filesystem like blkid do. We can run partclone.fstype to detect partition is vmfs or not, just run _$ ./partclone.fstype /dev/sda1 type: vmfs if partition is vmfs, fstype return string "type: vmfs" with exit "0". if not vmfs you can find reason with exit 1. * update files: modified: configure modified: src/Makefile.am modified: src/Makefile.in new file: src/fstype.c git-svn-id: svn+ssh://140.110.240.196/partclone_svn@360 93b75dfe-da2d-4241-a08d-2141769abc04 2010-02-14 steven Pack the release for 0.2.0-2. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@359 93b75dfe-da2d-4241-a08d-2141769abc04 2010-01-27 thomas * add vmfs check to autoconf * update vmfsclone modified: Makefile.in modified: aclocal.m4 modified: config.h.in modified: configure modified: configure.ac modified: docs/Makefile.in modified: po/zh_TW.gmo modified: po/zh_TW.po modified: src/Makefile.am modified: src/Makefile.in modified: src/version.h modified: src/vmfsclone.c git-svn-id: svn+ssh://140.110.240.196/partclone_svn@358 93b75dfe-da2d-4241-a08d-2141769abc04 2010-01-22 thomas The vmfsclone initial version. Just a experimental one can clone/restore vmfs partition. Thanks for vmfs-tools author, mike and cf. The vmfsclone shoud be keep update and do more testing. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@357 93b75dfe-da2d-4241-a08d-2141769abc04 2010-01-19 thomas * lose log mesg about bitmap_size and ntfs->lcnbmp_na->data_size data. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@356 93b75dfe-da2d-4241-a08d-2141769abc04 2010-01-18 thomas translate and smal update progress bar. modified: po/partclone.pot modified: po/zh_TW.gmo modified: po/zh_TW.po modified: src/progress.c git-svn-id: svn+ssh://140.110.240.196/partclone_svn@355 93b75dfe-da2d-4241-a08d-2141769abc04 update progress bar stop value. modified: src/ddclone.c modified: src/main.c modified: src/restore.c git-svn-id: svn+ssh://140.110.240.196/partclone_svn@354 93b75dfe-da2d-4241-a08d-2141769abc04 update progress bar. the new progress update by time. modified: src/ddclone.c modified: src/main.c modified: src/progress.c modified: src/progress.h modified: src/restore.c git-svn-id: svn+ssh://140.110.240.196/partclone_svn@353 93b75dfe-da2d-4241-a08d-2141769abc04 update ntfsclone-ng.c, accept and test the ntfs readbitmap patch, it's contributed by javor. Thank you. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@352 93b75dfe-da2d-4241-a08d-2141769abc04 2010-01-12 thomas update progress.c to fix avg rate number. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@351 93b75dfe-da2d-4241-a08d-2141769abc04 update progress bug, real done when finish procress. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@350 93b75dfe-da2d-4241-a08d-2141769abc04 2010-01-08 thomas * check the result of ntfs function call. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@349 93b75dfe-da2d-4241-a08d-2141769abc04 * update image_hdr for initializing. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@348 93b75dfe-da2d-4241-a08d-2141769abc04 2010-01-07 thomas * update version * initial image_hdr first Please enter the commit message for your changes. Lines starting with '#' will be ignored, and an empty message aborts the commit. On branch initial_image_hdr Changes to be committed: (use "git reset HEAD ..." to unstage) modified: configure modified: configure.ac modified: debian/changelog modified: po/partclone.pot modified: po/zh_TW.gmo modified: po/zh_TW.po modified: src/main.c modified: src/progress.c git-svn-id: svn+ssh://140.110.240.196/partclone_svn@347 93b75dfe-da2d-4241-a08d-2141769abc04 2010-01-06 thomas * add mtrace for debug * fix partclone.ntfs free/fs_close error, thank Javor reference: http://sourceforge.net/mailarchive/forum.php?thread_name=8e45d0591001051533n1378e8acvcbfd59c77ebca0de%40mail.gmail.com&forum_name=partclone-user * fix some memory leak problem. modified: src/main.c modified: src/ntfsclone-ng.c modified: src/partclone.c modified: src/version.h git-svn-id: svn+ssh://140.110.240.196/partclone_svn@346 93b75dfe-da2d-4241-a08d-2141769abc04 2010-01-05 thomas make sure progress bar show 100%. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@345 93b75dfe-da2d-4241-a08d-2141769abc04 2009-11-25 steven Updated for 0.1.9-5. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@344 93b75dfe-da2d-4241-a08d-2141769abc04 2009-11-19 thomas try to fix hfsplus error for 2 or more extents. modified: hfsplusclone.c git-svn-id: svn+ssh://140.110.240.196/partclone_svn@343 93b75dfe-da2d-4241-a08d-2141769abc04 2009-11-16 thomas update version number git-svn-id: svn+ssh://140.110.240.196/partclone_svn@342 93b75dfe-da2d-4241-a08d-2141769abc04 add control for ufs add changelog git-svn-id: svn+ssh://140.110.240.196/partclone_svn@341 93b75dfe-da2d-4241-a08d-2141769abc04 * update progress bar lang translation. * update ufs as default enabled file system. modified: configure modified: configure.ac modified: po/partclone.pot modified: po/zh_TW.gmo modified: po/zh_TW.po git-svn-id: svn+ssh://140.110.240.196/partclone_svn@340 93b75dfe-da2d-4241-a08d-2141769abc04 test progress 1 modified: src/progress.c git-svn-id: svn+ssh://140.110.240.196/partclone_svn@339 93b75dfe-da2d-4241-a08d-2141769abc04 2009-11-03 steven partclone (0.1.9-3) unstable; urgency=low [ Yu-Chin Tsai ] * An option to ignore CRC checking was added. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@338 93b75dfe-da2d-4241-a08d-2141769abc04 2009-11-02 thomas update ignore_crc in main.c add ignore_crc to restore.c DON'T IGNORE CRC in 64BIT IMAGE !!! git-svn-id: svn+ssh://140.110.240.196/partclone_svn@337 93b75dfe-da2d-4241-a08d-2141769abc04 2009-10-09 steven Updated changelog for partclone 0.1.9-2. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@336 93b75dfe-da2d-4241-a08d-2141769abc04 2009-10-06 thomas update log message and open fail message for ufsclone. Thank dswartz for testing ufs backup and report. modified: src/ufsclone.c git-svn-id: svn+ssh://140.110.240.196/partclone_svn@335 93b75dfe-da2d-4241-a08d-2141769abc04 2009-10-02 thomas bug fix for ufscline git-svn-id: svn+ssh://140.110.240.196/partclone_svn@334 93b75dfe-da2d-4241-a08d-2141769abc04 update option value git-svn-id: svn+ssh://140.110.240.196/partclone_svn@333 93b75dfe-da2d-4241-a08d-2141769abc04 add ignore fschk for xfs. modified: xfsclone.c git-svn-id: svn+ssh://140.110.240.196/partclone_svn@332 93b75dfe-da2d-4241-a08d-2141769abc04 2009-09-27 thomas add option Ignore_crc, but need more test. fix bug of --rescue update malloc for I/O performance modified: src/ddclone.c modified: src/main.c modified: src/partclone.c modified: src/partclone.h modified: src/restore.c modified: src/version.h git-svn-id: svn+ssh://140.110.240.196/partclone_svn@331 93b75dfe-da2d-4241-a08d-2141769abc04 2009-09-22 thomas add ufs include dir On branch master new file: ufs/ffs/fs.h new file: ufs/libufs.h new file: ufs/sys/disklabel.h new file: ufs/ufs/dinode.h new file: ufs/ufs/fs.h git-svn-id: svn+ssh://140.110.240.196/partclone_svn@330 93b75dfe-da2d-4241-a08d-2141769abc04 update ufsclone merge error. On branch master Changes to be committed: modified: src/ufsclone.c git-svn-id: svn+ssh://140.110.240.196/partclone_svn@329 93b75dfe-da2d-4241-a08d-2141769abc04 fix hfsplus message modified: src/hfsplusclone.c git-svn-id: svn+ssh://140.110.240.196/partclone_svn@328 93b75dfe-da2d-4241-a08d-2141769abc04 update fs log message. add ignore option to all supported file system. Changes to be committed: (use "git reset HEAD ..." to unstage) modified: extfsclone.c modified: fatclone.c modified: hfsplusclone.c modified: ntfsclone-ng.c modified: reiser4clone.c modified: reiserfsclone.c modified: ufsclone.c modified: xfsclone.c git-svn-id: svn+ssh://140.110.240.196/partclone_svn@327 93b75dfe-da2d-4241-a08d-2141769abc04 ignore fschk fro extfs modified: extfsclone.c git-svn-id: svn+ssh://140.110.240.196/partclone_svn@326 93b75dfe-da2d-4241-a08d-2141769abc04 New feature: ignore file system check for reiserfs, -I or --ignore_fschk. On branch log Changes to be committed: new file: fs_common.h modified: main.c modified: partclone.c modified: partclone.h modified: reiserfsclone.c git-svn-id: svn+ssh://140.110.240.196/partclone_svn@325 93b75dfe-da2d-4241-a08d-2141769abc04 2009-09-18 steven updated for 0.1.9-1. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@324 93b75dfe-da2d-4241-a08d-2141769abc04 2009-09-17 thomas update changelog to test svn-buildpackage git-svn-id: svn+ssh://140.110.240.196/partclone_svn@323 93b75dfe-da2d-4241-a08d-2141769abc04 * update version * update log git-svn-id: svn+ssh://140.110.240.196/partclone_svn@322 93b75dfe-da2d-4241-a08d-2141769abc04 2009-09-14 thomas ufs test ok. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@321 93b75dfe-da2d-4241-a08d-2141769abc04 update for checking ufs status. Committer: thomas On branch master Changes to be committed: (use "git reset HEAD ..." to unstage) modified: src/ufsclone.c modified: src/ufsclone.h git-svn-id: svn+ssh://140.110.240.196/partclone_svn@320 93b75dfe-da2d-4241-a08d-2141769abc04 update configure.ac git-svn-id: svn+ssh://140.110.240.196/partclone_svn@319 93b75dfe-da2d-4241-a08d-2141769abc04 Committer: thomas On branch master Changes to be committed: (use "git reset HEAD ..." to unstage) modified: src/xfsclone.c bug fix for xfs clone fail. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@318 93b75dfe-da2d-4241-a08d-2141769abc04 2009-09-07 thomas add autotool script for ufs. The option --enable-all not include ufs right now. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@317 93b75dfe-da2d-4241-a08d-2141769abc04 2009-09-03 thomas first time ufs back/restore successfully. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@316 93b75dfe-da2d-4241-a08d-2141769abc04 update automake andd ufsclone git-svn-id: svn+ssh://140.110.240.196/partclone_svn@315 93b75dfe-da2d-4241-a08d-2141769abc04 Merge 140.110.240.52:/home/partimag/workspace/partclone git-svn-id: svn+ssh://140.110.240.196/partclone_svn@314 93b75dfe-da2d-4241-a08d-2141769abc04 2009-08-10 thomas update version function update usage git-svn-id: svn+ssh://140.110.240.196/partclone_svn@313 93b75dfe-da2d-4241-a08d-2141769abc04 update svn version git-svn-id: svn+ssh://140.110.240.196/partclone_svn@312 93b75dfe-da2d-4241-a08d-2141769abc04 2009-08-09 steven * Bug fixed: FAT clone failure was fixed. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@311 93b75dfe-da2d-4241-a08d-2141769abc04 2009-07-31 thomas update fat problem! fix bug about fat clone fail. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@310 93b75dfe-da2d-4241-a08d-2141769abc04 2009-06-24 steven updated for 0.1.1-15. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@309 93b75dfe-da2d-4241-a08d-2141769abc04 updated for 0.1.1-15 git-svn-id: svn+ssh://140.110.240.196/partclone_svn@308 93b75dfe-da2d-4241-a08d-2141769abc04 2009-06-24 thomas remove Makefile git-svn-id: svn+ssh://140.110.240.196/partclone_svn@307 93b75dfe-da2d-4241-a08d-2141769abc04 2009-06-24 steven updated for version 0.1.1-14. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@306 93b75dfe-da2d-4241-a08d-2141769abc04 2009-06-24 thomas update makefile for version.h git-svn-id: svn+ssh://140.110.240.196/partclone_svn@305 93b75dfe-da2d-4241-a08d-2141769abc04 2009-06-19 steven Updated for version 0.1.1-13. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@304 93b75dfe-da2d-4241-a08d-2141769abc04 2009-06-19 thomas Merge branch 'test' git-svn-id: svn+ssh://140.110.240.196/partclone_svn@303 93b75dfe-da2d-4241-a08d-2141769abc04 Merge branch 'test' git-svn-id: svn+ssh://140.110.240.196/partclone_svn@302 93b75dfe-da2d-4241-a08d-2141769abc04 Merge branch 'test' Conflicts: partclone/src/version.c git-svn-id: svn+ssh://140.110.240.196/partclone_svn@301 93b75dfe-da2d-4241-a08d-2141769abc04 2009-06-17 steven Updated for version 0.1.1-12. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@300 93b75dfe-da2d-4241-a08d-2141769abc04 Updated for version 0.1.1-12. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@299 93b75dfe-da2d-4241-a08d-2141769abc04 2009-06-16 thomas update Makefile in debian lenny update src/chkimg.c git-svn-id: svn+ssh://140.110.240.196/partclone_svn@298 93b75dfe-da2d-4241-a08d-2141769abc04 add option --logfile or -L to specify file for log message. update Makefile for chkimg modified: Makefile.in modified: aclocal.m4 modified: configure modified: docs/Makefile.in new file: src/Makefile modified: src/chkimg.c new file: src/config.h modified: src/ddclone.c modified: src/infoclone.c modified: src/main.c modified: src/partclone.c modified: src/partclone.h modified: src/restore.c git-svn-id: svn+ssh://140.110.240.196/partclone_svn@297 93b75dfe-da2d-4241-a08d-2141769abc04 The partclone.chkimg could help you check img by CRC. modified: src/Makefile.am modified: src/Makefile.in new file: src/chkimg.c git-svn-id: svn+ssh://140.110.240.196/partclone_svn@296 93b75dfe-da2d-4241-a08d-2141769abc04 2009-06-13 steven Updated for version 0.1.1-11. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@295 93b75dfe-da2d-4241-a08d-2141769abc04 2009-06-10 thomas update clear_buf git-svn-id: svn+ssh://140.110.240.196/partclone_svn@294 93b75dfe-da2d-4241-a08d-2141769abc04 accept patch from Kristian Erik Hermansen. fix progress.c:152 SECURITY: fprintf call should have "%s" as argument 1 git-svn-id: svn+ssh://140.110.240.196/partclone_svn@293 93b75dfe-da2d-4241-a08d-2141769abc04 2009-06-10 steven Updated for 0.1.1-10. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@292 93b75dfe-da2d-4241-a08d-2141769abc04 2009-06-09 thomas update pointer problem modified: src/progress.c modified: src/restore.c git-svn-id: svn+ssh://140.110.240.196/partclone_svn@291 93b75dfe-da2d-4241-a08d-2141769abc04 update message and hfsplus modified: src/hfsplusclone.c modified: src/main.c modified: src/version.c git-svn-id: svn+ssh://140.110.240.196/partclone_svn@290 93b75dfe-da2d-4241-a08d-2141769abc04 try to fix hfsplus problem-1 modified: src/hfsplusclone.c git-svn-id: svn+ssh://140.110.240.196/partclone_svn@289 93b75dfe-da2d-4241-a08d-2141769abc04 2009-06-08 thomas update tmp_str scale to 512. tkx Kristian Erik Hermansen and Piavlo Re: [Clonezilla-user] partclone v0.1.0 - buffer overflow detected git-svn-id: svn+ssh://140.110.240.196/partclone_svn@288 93b75dfe-da2d-4241-a08d-2141769abc04 remove message done! git-svn-id: svn+ssh://140.110.240.196/partclone_svn@287 93b75dfe-da2d-4241-a08d-2141769abc04 2009-06-02 steven * Some output messages were polished again. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@286 93b75dfe-da2d-4241-a08d-2141769abc04 Output messages of restoring were updated. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@285 93b75dfe-da2d-4241-a08d-2141769abc04 Output message when restoring will be shown as "Please wait... done!" git-svn-id: svn+ssh://140.110.240.196/partclone_svn@284 93b75dfe-da2d-4241-a08d-2141769abc04 Updated for version 0.1.1-8. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@283 93b75dfe-da2d-4241-a08d-2141769abc04 2009-06-02 thomas update message for restore git-svn-id: svn+ssh://140.110.240.196/partclone_svn@282 93b75dfe-da2d-4241-a08d-2141769abc04 update: add "done" after "please wait" git-svn-id: svn+ssh://140.110.240.196/partclone_svn@281 93b75dfe-da2d-4241-a08d-2141769abc04 update: add new line after Please wait... modified: main.c git-svn-id: svn+ssh://140.110.240.196/partclone_svn@280 93b75dfe-da2d-4241-a08d-2141769abc04 2009-06-01 steven Updated for 0.1.1-7. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@279 93b75dfe-da2d-4241-a08d-2141769abc04 updated for partclone 0.1.1-7. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@278 93b75dfe-da2d-4241-a08d-2141769abc04 2009-06-01 thomas fix bug for progress update with nogui add "Calculating bitmap..." without -d option git-svn-id: svn+ssh://140.110.240.196/partclone_svn@277 93b75dfe-da2d-4241-a08d-2141769abc04 2009-05-30 steven Updated for version 0.1.1-6 git-svn-id: svn+ssh://140.110.240.196/partclone_svn@276 93b75dfe-da2d-4241-a08d-2141769abc04 2009-05-28 thomas update for 64 bit I found a crc problem and should be fix in the next image version. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@275 93b75dfe-da2d-4241-a08d-2141769abc04 update crc in 64 bit image problem again... git-svn-id: svn+ssh://140.110.240.196/partclone_svn@274 93b75dfe-da2d-4241-a08d-2141769abc04 2009-05-27 steven Updated for 0.1.1-5. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@273 93b75dfe-da2d-4241-a08d-2141769abc04 2009-05-27 thomas bug of time calculating git-svn-id: svn+ssh://140.110.240.196/partclone_svn@272 93b75dfe-da2d-4241-a08d-2141769abc04 2009-05-27 steven Updated for version 0.1.1-4. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@271 93b75dfe-da2d-4241-a08d-2141769abc04 * Update default RES from 10000 to 1000. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@270 93b75dfe-da2d-4241-a08d-2141769abc04 2009-05-27 thomas update default RES from 10000 to 1000 git-svn-id: svn+ssh://140.110.240.196/partclone_svn@269 93b75dfe-da2d-4241-a08d-2141769abc04 2009-05-27 steven updated for 0.1.1-3 git-svn-id: svn+ssh://140.110.240.196/partclone_svn@268 93b75dfe-da2d-4241-a08d-2141769abc04 2009-05-27 thomas test for open block file git-svn-id: svn+ssh://140.110.240.196/partclone_svn@267 93b75dfe-da2d-4241-a08d-2141769abc04 2009-05-22 steven updated for 0.1.1-2 git-svn-id: svn+ssh://140.110.240.196/partclone_svn@266 93b75dfe-da2d-4241-a08d-2141769abc04 updated for partclone (0.1.1-2). git-svn-id: svn+ssh://140.110.240.196/partclone_svn@265 93b75dfe-da2d-4241-a08d-2141769abc04 2009-05-22 thomas add link of partclone.ntfsreloc git-svn-id: svn+ssh://140.110.240.196/partclone_svn@264 93b75dfe-da2d-4241-a08d-2141769abc04 It's possible to create new file as target for restore after this commit... git-svn-id: svn+ssh://140.110.240.196/partclone_svn@263 93b75dfe-da2d-4241-a08d-2141769abc04 2009-05-21 thomas add argument -f, --UI-fresh to set fresh time of progress bar ex: -f 10 // set fresh progress per 10*100 blocks The default fresh is 10000... git-svn-id: svn+ssh://140.110.240.196/partclone_svn@262 93b75dfe-da2d-4241-a08d-2141769abc04 update for xfs progress git-svn-id: svn+ssh://140.110.240.196/partclone_svn@261 93b75dfe-da2d-4241-a08d-2141769abc04 pre release... git-svn-id: svn+ssh://140.110.240.196/partclone_svn@260 93b75dfe-da2d-4241-a08d-2141769abc04 update CRC read error message git-svn-id: svn+ssh://140.110.240.196/partclone_svn@259 93b75dfe-da2d-4241-a08d-2141769abc04 update progress init git-svn-id: svn+ssh://140.110.240.196/partclone_svn@258 93b75dfe-da2d-4241-a08d-2141769abc04 2009-05-20 thomas update for pui git-svn-id: svn+ssh://140.110.240.196/partclone_svn@257 93b75dfe-da2d-4241-a08d-2141769abc04 * update version git-svn-id: svn+ssh://140.110.240.196/partclone_svn@256 93b75dfe-da2d-4241-a08d-2141769abc04 * add progress for bitmap * update structure of progress * update structure of Ncurses... git-svn-id: svn+ssh://140.110.240.196/partclone_svn@255 93b75dfe-da2d-4241-a08d-2141769abc04 * Before this commit, partclone restore fail from 64 bit img to 32 bit. It's because the size of Unsigned long is 8 bytes in 64 bit, and 4 bytes in 32 bit partclone. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@254 93b75dfe-da2d-4241-a08d-2141769abc04 update crc test git-svn-id: svn+ssh://140.110.240.196/partclone_svn@253 93b75dfe-da2d-4241-a08d-2141769abc04 2009-05-19 thomas * display progress bar when readbitmap * normalize update time, but could be better git-svn-id: svn+ssh://140.110.240.196/partclone_svn@252 93b75dfe-da2d-4241-a08d-2141769abc04 test progress of bitmap git-svn-id: svn+ssh://140.110.240.196/partclone_svn@251 93b75dfe-da2d-4241-a08d-2141769abc04 2009-05-14 thomas * add print_partclone_info() * add more informatio to stderr * check all utilities work right git-svn-id: svn+ssh://140.110.240.196/partclone_svn@250 93b75dfe-da2d-4241-a08d-2141769abc04 add more information to know the process modified: main.c modified: partclone.c git-svn-id: svn+ssh://140.110.240.196/partclone_svn@249 93b75dfe-da2d-4241-a08d-2141769abc04 2009-05-05 thomas remove ntfsreloc git-svn-id: svn+ssh://140.110.240.196/partclone_svn@248 93b75dfe-da2d-4241-a08d-2141769abc04 add ntfsfixboot.c from http://cc.jct.ac.il/~shaneh/ntfsfixboot.c git-svn-id: svn+ssh://140.110.240.196/partclone_svn@247 93b75dfe-da2d-4241-a08d-2141769abc04 2009-05-01 steven updated for 0.1.0-10. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@246 93b75dfe-da2d-4241-a08d-2141769abc04 * Bug fixed: clonezilla-Bugs-2784676. Thanks to njorl _at_ users sourceforge net. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@245 93b75dfe-da2d-4241-a08d-2141769abc04 changelog updated for bug fixed: clonezilla-Bugs-2784676. Thanks to njorl _at_ users sourceforge net. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@244 93b75dfe-da2d-4241-a08d-2141769abc04 2009-05-01 thomas update for fs_open git-svn-id: svn+ssh://140.110.240.196/partclone_svn@243 93b75dfe-da2d-4241-a08d-2141769abc04 2009-04-29 thomas update po git-svn-id: svn+ssh://140.110.240.196/partclone_svn@242 93b75dfe-da2d-4241-a08d-2141769abc04 2009-04-27 steven zh_TW po related files were updated. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@241 93b75dfe-da2d-4241-a08d-2141769abc04 2009-04-26 steven version.c automatically updated for 0.1.0-9. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@240 93b75dfe-da2d-4241-a08d-2141769abc04 Changelogs were updated for 0.1.0-9. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@239 93b75dfe-da2d-4241-a08d-2141769abc04 2009-04-25 steven Output message "clone successfully" was changed as "Cloned successfully.". git-svn-id: svn+ssh://140.110.240.196/partclone_svn@238 93b75dfe-da2d-4241-a08d-2141769abc04 2009-04-24 steven Updated for 0.1.0-8. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@237 93b75dfe-da2d-4241-a08d-2141769abc04 2009-04-24 thomas add EXECNAME git-svn-id: svn+ssh://140.110.240.196/partclone_svn@236 93b75dfe-da2d-4241-a08d-2141769abc04 2009-04-24 steven "clone successfully" was changed to "Successfully cloned." git-svn-id: svn+ssh://140.110.240.196/partclone_svn@235 93b75dfe-da2d-4241-a08d-2141769abc04 2009-04-23 steven updated for 0.1.0-7 git-svn-id: svn+ssh://140.110.240.196/partclone_svn@234 93b75dfe-da2d-4241-a08d-2141769abc04 2009-04-23 thomas add link partclone.ext4dev git-svn-id: svn+ssh://140.110.240.196/partclone_svn@233 93b75dfe-da2d-4241-a08d-2141769abc04 2009-04-18 steven Updated. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@232 93b75dfe-da2d-4241-a08d-2141769abc04 Updated for version 0.1.0-6. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@231 93b75dfe-da2d-4241-a08d-2141769abc04 2009-04-17 thomas fix partclone.restore can't get source data from pipe which is organized FS. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@230 93b75dfe-da2d-4241-a08d-2141769abc04 update po files git-svn-id: svn+ssh://140.110.240.196/partclone_svn@229 93b75dfe-da2d-4241-a08d-2141769abc04 2009-04-16 thomas update check fs type and error message for reiser4, reiserfs, xfs, ntfs and extfs. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@228 93b75dfe-da2d-4241-a08d-2141769abc04 2009-04-16 steven www.partclone.org was changed to partclone.org. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@227 93b75dfe-da2d-4241-a08d-2141769abc04 Updated for partclone 0.1.0-5 git-svn-id: svn+ssh://140.110.240.196/partclone_svn@226 93b75dfe-da2d-4241-a08d-2141769abc04 2009-04-16 thomas * update ext2/3/4 message * fix bug, update check_size return value git-svn-id: svn+ssh://140.110.240.196/partclone_svn@225 93b75dfe-da2d-4241-a08d-2141769abc04 2009-04-16 steven Update chnagelog for release 0.1.0-4 git-svn-id: svn+ssh://140.110.240.196/partclone_svn@224 93b75dfe-da2d-4241-a08d-2141769abc04 2009-04-16 thomas update * EXECNAME in xxxclone.c * change description of dd-mode as dev-to-dev Local copy... * fix bug about get_partition size git-svn-id: svn+ssh://140.110.240.196/partclone_svn@223 93b75dfe-da2d-4241-a08d-2141769abc04 2009-04-15 steven [ Thomas Tsai ] * Bug fixed: partclone.ntfs statistics data was wrong when doing partition to partition clone. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@222 93b75dfe-da2d-4241-a08d-2141769abc04 2009-04-15 thomas update xfs unknow to unknown git-svn-id: svn+ssh://140.110.240.196/partclone_svn@221 93b75dfe-da2d-4241-a08d-2141769abc04 update #include git-svn-id: svn+ssh://140.110.240.196/partclone_svn@220 93b75dfe-da2d-4241-a08d-2141769abc04 * update for #49, configure error with FC10 * try to fix ntfs used space git-svn-id: svn+ssh://140.110.240.196/partclone_svn@219 93b75dfe-da2d-4241-a08d-2141769abc04 2009-04-10 steven * --enable-static is on again. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@218 93b75dfe-da2d-4241-a08d-2141769abc04 * Disable static linking * e2fslibs-dev (>= 1.41.3) is required for partclone.ext4. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@217 93b75dfe-da2d-4241-a08d-2141769abc04 2009-04-10 thomas add ext4 link again.... git-svn-id: svn+ssh://140.110.240.196/partclone_svn@216 93b75dfe-da2d-4241-a08d-2141769abc04 2009-04-07 thomas r341@T-X61: thomas | 2009-04-07 23:06:22 +0800 update Makefile.am: add pthread link for build static partclone.extfs with Debiab/lenny. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@215 93b75dfe-da2d-4241-a08d-2141769abc04 update ChangeLog git-svn-id: svn+ssh://140.110.240.196/partclone_svn@214 93b75dfe-da2d-4241-a08d-2141769abc04 2009-04-03 thomas update progress.c set default progress update threshold as 10. partclone update progress bar per 10 copied blocks. but the performance not speedup. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@213 93b75dfe-da2d-4241-a08d-2141769abc04 test version for better performance: Idea 1: decrease the count of progress_update git-svn-id: svn+ssh://140.110.240.196/partclone_svn@212 93b75dfe-da2d-4241-a08d-2141769abc04 2009-04-01 thomas The unstable version has merged to stable and move to backup. The testing is branch from stable. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@211 93b75dfe-da2d-4241-a08d-2141769abc04 2009-03-31 thomas update make file * add partclone.ext4 link git-svn-id: svn+ssh://140.110.240.196/partclone_svn@210 93b75dfe-da2d-4241-a08d-2141769abc04 2009-03-12 thomas update size of device and volume git-svn-id: svn+ssh://140.110.240.196/partclone_svn@209 93b75dfe-da2d-4241-a08d-2141769abc04 2009-03-05 thomas merger from unstable git-svn-id: svn+ssh://140.110.240.196/partclone_svn@208 93b75dfe-da2d-4241-a08d-2141769abc04 r214@T-X61: thomas | 2009-03-05 02:54:25 +0800 update configure by autoreconf update partclone.c * return 0 from io_all to check EOF * can't vfprintf twice between va_start to va_end in log_mesg git-svn-id: svn+ssh://140.110.240.196/partclone_svn@207 93b75dfe-da2d-4241-a08d-2141769abc04 update for va_start, make sure vsprintf is right for x86_64 git-svn-id: svn+ssh://140.110.240.196/partclone_svn@206 93b75dfe-da2d-4241-a08d-2141769abc04 2009-03-04 thomas update deplib_version.c to check library version git-svn-id: svn+ssh://140.110.240.196/partclone_svn@205 93b75dfe-da2d-4241-a08d-2141769abc04 update configure for ext4 git-svn-id: svn+ssh://140.110.240.196/partclone_svn@204 93b75dfe-da2d-4241-a08d-2141769abc04 update configure.ac git-svn-id: svn+ssh://140.110.240.196/partclone_svn@203 93b75dfe-da2d-4241-a08d-2141769abc04 back to r198 git-svn-id: svn+ssh://140.110.240.196/partclone_svn@202 93b75dfe-da2d-4241-a08d-2141769abc04 git-svn-id: svn+ssh://140.110.240.196/partclone_svn@201 93b75dfe-da2d-4241-a08d-2141769abc04 update for lib reiser4 git-svn-id: svn+ssh://140.110.240.196/partclone_svn@200 93b75dfe-da2d-4241-a08d-2141769abc04 add partclone.ext4 git-svn-id: svn+ssh://140.110.240.196/partclone_svn@199 93b75dfe-da2d-4241-a08d-2141769abc04 update confiure git-svn-id: svn+ssh://140.110.240.196/partclone_svn@198 93b75dfe-da2d-4241-a08d-2141769abc04 r201@T-X61: thomas | 2009-03-04 00:46:06 +0800 test by svk git-svn-id: svn+ssh://140.110.240.196/partclone_svn@197 93b75dfe-da2d-4241-a08d-2141769abc04 2009-03-02 thomas add unstable/src/deplib_version.c to replace unstable/src/ntfs_version.c update configure to check library version ex: reiser4, reiserfs, extfs and ntfs. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@196 93b75dfe-da2d-4241-a08d-2141769abc04 add src/deplib_version.c to check library version for configuration. remove src/ntfs_version.c and cheange to use src/deplib_version.c . git-svn-id: svn+ssh://140.110.240.196/partclone_svn@195 93b75dfe-da2d-4241-a08d-2141769abc04 2009-02-05 thomas create a unstable branch git-svn-id: svn+ssh://140.110.240.196/partclone_svn@194 93b75dfe-da2d-4241-a08d-2141769abc04 update debug level git-svn-id: svn+ssh://140.110.240.196/partclone_svn@193 93b75dfe-da2d-4241-a08d-2141769abc04 fix bug for bitmap git-svn-id: svn+ssh://140.110.240.196/partclone_svn@192 93b75dfe-da2d-4241-a08d-2141769abc04 fix check_valid fs git-svn-id: svn+ssh://140.110.240.196/partclone_svn@191 93b75dfe-da2d-4241-a08d-2141769abc04 2009-02-04 thomas try to fix bug of ext4 git-svn-id: svn+ssh://140.110.240.196/partclone_svn@190 93b75dfe-da2d-4241-a08d-2141769abc04 2009-01-20 thomas update restore.c to support restore stdin raw file git-svn-id: svn+ssh://140.110.240.196/partclone_svn@189 93b75dfe-da2d-4241-a08d-2141769abc04 2009-01-19 thomas make partclone.dd can read stdin to restore date git-svn-id: svn+ssh://140.110.240.196/partclone_svn@188 93b75dfe-da2d-4241-a08d-2141769abc04 update for ext4 git-svn-id: svn+ssh://140.110.240.196/partclone_svn@187 93b75dfe-da2d-4241-a08d-2141769abc04 2009-01-16 thomas add partclone.dd and partclone.restore. partclone.dd set all block as used and save/restore device to/from raw data. partclone.restore is used to restore device from raw data or image build from partclone. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@186 93b75dfe-da2d-4241-a08d-2141769abc04 2009-01-12 thomas * add option force progress! use -F/--force to keep progress and just warrning for memory, disk and FS problem but dangerous. * add restore utility to restore any image which is made by partclone. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@185 93b75dfe-da2d-4241-a08d-2141769abc04 2008-12-30 steven * A bug about FAT12 was fixed. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@184 93b75dfe-da2d-4241-a08d-2141769abc04 2008-12-29 thomas update fat12 bug. The Fat 12 is ready now! git-svn-id: svn+ssh://140.110.240.196/partclone_svn@183 93b75dfe-da2d-4241-a08d-2141769abc04 2008-12-25 steven * New upstream ntfsreloc.c 0.8. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@182 93b75dfe-da2d-4241-a08d-2141769abc04 2008-12-22 steven updated with 0.0.9-2. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@181 93b75dfe-da2d-4241-a08d-2141769abc04 Updated for 0.0.9-2 git-svn-id: svn+ssh://140.110.240.196/partclone_svn@180 93b75dfe-da2d-4241-a08d-2141769abc04 2008-12-03 thomas update fatclone.c fatclone.h clearly. update dirty message for extfs. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@179 93b75dfe-da2d-4241-a08d-2141769abc04 2008-11-18 thomas add check FAT filesystem before clone volume. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@178 93b75dfe-da2d-4241-a08d-2141769abc04 2008-11-17 thomas add check hfs_plus filesystem before clone volume. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@177 93b75dfe-da2d-4241-a08d-2141769abc04 2008-11-11 thomas check filesystem before clone partition. Partclone will make sure reiserfs, ext2/3/4, reiser4 and ntfs is clean before copy data. The check of fat, xfs and hfsplus is developing. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@176 93b75dfe-da2d-4241-a08d-2141769abc04 2008-11-07 thomas update dirty message for ntfsclone-ng git-svn-id: svn+ssh://140.110.240.196/partclone_svn@175 93b75dfe-da2d-4241-a08d-2141769abc04 2008-10-30 thomas * remove get_ntfs_version, and always compile get_ntfs_version by configure * make ntfsclone-ng.c support libntfs version 9 and 10 * never check used block between bitmap and super_block except option "-d2" git-svn-id: svn+ssh://140.110.240.196/partclone_svn@174 93b75dfe-da2d-4241-a08d-2141769abc04 update for old libntfs(9) at debian etch git-svn-id: svn+ssh://140.110.240.196/partclone_svn@173 93b75dfe-da2d-4241-a08d-2141769abc04 update configure to check ntfs_version git-svn-id: svn+ssh://140.110.240.196/partclone_svn@172 93b75dfe-da2d-4241-a08d-2141769abc04 fix get_ntfs_version to get right version number git-svn-id: svn+ssh://140.110.240.196/partclone_svn@171 93b75dfe-da2d-4241-a08d-2141769abc04 2008-10-30 steven debian/changelog and README were updated. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@170 93b75dfe-da2d-4241-a08d-2141769abc04 2008-10-30 thomas add man for ntfs git-svn-id: svn+ssh://140.110.240.196/partclone_svn@169 93b75dfe-da2d-4241-a08d-2141769abc04 2008-10-22 thomas update ntfsclone upgrade version to 0.0.9 git-svn-id: svn+ssh://140.110.240.196/partclone_svn@168 93b75dfe-da2d-4241-a08d-2141769abc04 2008-10-21 thomas add src/ntfsreloc.c for partclone.ntfsreloc. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@167 93b75dfe-da2d-4241-a08d-2141769abc04 update segmentation fail for log_mesg in X86_64. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@166 93b75dfe-da2d-4241-a08d-2141769abc04 2008-10-20 thomas update configure to check libntfs version. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@165 93b75dfe-da2d-4241-a08d-2141769abc04 Add get_ntfs_version, src/ntfs_version.c to check libntfs version. update src/ntfsclone-ng.c for bitmap bug git-svn-id: svn+ssh://140.110.240.196/partclone_svn@164 93b75dfe-da2d-4241-a08d-2141769abc04 2008-10-16 thomas add ntfsreloc.c from linux-ntfs. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@163 93b75dfe-da2d-4241-a08d-2141769abc04 try to support ntfs, the ntfsclone-ng is unstable now. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@162 93b75dfe-da2d-4241-a08d-2141769abc04 try to support NTFS filesystem. unstable!!! git-svn-id: svn+ssh://140.110.240.196/partclone_svn@161 93b75dfe-da2d-4241-a08d-2141769abc04 2008-07-30 c00jhs00 update for 0.8.8 release. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@160 93b75dfe-da2d-4241-a08d-2141769abc04 2008-07-29 thomas fix-bug for fat 32 file system. The error will calculate wrong bitmap number. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@159 93b75dfe-da2d-4241-a08d-2141769abc04 2008-07-24 thomas update Makefile.am for amd64 compile with static problem. I add -lcom_err to fix "undefined reference tp 'com_err ". see #16 git-svn-id: svn+ssh://140.110.240.196/partclone_svn@158 93b75dfe-da2d-4241-a08d-2141769abc04 2008-07-24 c00jhs00 updated notes for 0.0.8-7. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@157 93b75dfe-da2d-4241-a08d-2141769abc04 2008-07-24 thomas add partclone.pfsplus link. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@156 93b75dfe-da2d-4241-a08d-2141769abc04 2008-07-11 c00jhs00 # Bug fixed: partclone.fat12 link was not done. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@155 93b75dfe-da2d-4241-a08d-2141769abc04 2008-07-11 thomas update makefile to link fat12 git-svn-id: svn+ssh://140.110.240.196/partclone_svn@154 93b75dfe-da2d-4241-a08d-2141769abc04 2008-07-11 c00jhs00 # fat12 was added by Thomas Tsai. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@153 93b75dfe-da2d-4241-a08d-2141769abc04 2008-07-10 thomas try to make partclone support fat12 git-svn-id: svn+ssh://140.110.240.196/partclone_svn@152 93b75dfe-da2d-4241-a08d-2141769abc04 2008-06-28 c00jhs00 # Enable static linking. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@151 93b75dfe-da2d-4241-a08d-2141769abc04 2008-06-15 c00jhs00 Changelog updated for 0.8.2-3. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@150 93b75dfe-da2d-4241-a08d-2141769abc04 2008-06-15 thomas update for net TUI tickets: #35, Add a message like "Waiting for image" or "Please wait..." after "Calculating bitmap..." #37, Make all the words in Chinese the same - å°è±¡æª” #38, typos git-svn-id: svn+ssh://140.110.240.196/partclone_svn@149 93b75dfe-da2d-4241-a08d-2141769abc04 2008-05-25 thomas * update configure.ac to check ncurses well at different dists. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@148 93b75dfe-da2d-4241-a08d-2141769abc04 2008-05-25 c00jhs00 - partclone.sourceforge.net is replaced by www.partclone.org. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@147 93b75dfe-da2d-4241-a08d-2141769abc04 # clone.$FS was renamed as partclone.$FS by Thomas Tsai. # Version number now is 0.0.8. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@146 93b75dfe-da2d-4241-a08d-2141769abc04 2008-05-22 thomas * update dics files git-svn-id: svn+ssh://140.110.240.196/partclone_svn@145 93b75dfe-da2d-4241-a08d-2141769abc04 2008-05-20 thomas * rename man file for partclone git-svn-id: svn+ssh://140.110.240.196/partclone_svn@144 93b75dfe-da2d-4241-a08d-2141769abc04 2008-05-19 thomas * erase window to make terminal clean git-svn-id: svn+ssh://140.110.240.196/partclone_svn@143 93b75dfe-da2d-4241-a08d-2141769abc04 * fix color for probress bar git-svn-id: svn+ssh://140.110.240.196/partclone_svn@142 93b75dfe-da2d-4241-a08d-2141769abc04 * try to fix strange bug for ncurses.(http://www.stevenshiau.org/misc/partclone/partclone2.png) git-svn-id: svn+ssh://140.110.240.196/partclone_svn@141 93b75dfe-da2d-4241-a08d-2141769abc04 * accept ticket #33, and update configure, *am, *in files. * make all clone tools can restore any image which is created by partclone. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@140 93b75dfe-da2d-4241-a08d-2141769abc04 2008-05-16 c00jhs00 change updated for 0.0.7-4 git-svn-id: svn+ssh://140.110.240.196/partclone_svn@139 93b75dfe-da2d-4241-a08d-2141769abc04 2008-05-16 thomas * fix the latest terminal(64*24) size for ncurses * chage the color to partimage style. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@138 93b75dfe-da2d-4241-a08d-2141769abc04 2008-05-14 thomas update TUI * set background and font color * set window postition always at center * leave message on stderr when clone fail or success * If you want to use TUI, the latest terminal size should be 64x26 git-svn-id: svn+ssh://140.110.240.196/partclone_svn@137 93b75dfe-da2d-4241-a08d-2141769abc04 2008-05-11 c00jhs00 changelog for version 0.0.7-3 git-svn-id: svn+ssh://140.110.240.196/partclone_svn@136 93b75dfe-da2d-4241-a08d-2141769abc04 2008-05-07 thomas fix bug for #30 * change to txet mode if terminal color error * change to text mode if terminal width and height too small git-svn-id: svn+ssh://140.110.240.196/partclone_svn@135 93b75dfe-da2d-4241-a08d-2141769abc04 2008-05-01 thomas * update progress bar when the terminal not work at color style git-svn-id: svn+ssh://140.110.240.196/partclone_svn@134 93b75dfe-da2d-4241-a08d-2141769abc04 2008-05-01 c00jhs00 auto updated. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@133 93b75dfe-da2d-4241-a08d-2141769abc04 libncursesw5-dev was added for Build-Depends. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@132 93b75dfe-da2d-4241-a08d-2141769abc04 # Use --enable-ncursesw by default. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@131 93b75dfe-da2d-4241-a08d-2141769abc04 2008-05-01 thomas * update version number git-svn-id: svn+ssh://140.110.240.196/partclone_svn@130 93b75dfe-da2d-4241-a08d-2141769abc04 2008-04-30 thomas * add more information for dialog git-svn-id: svn+ssh://140.110.240.196/partclone_svn@129 93b75dfe-da2d-4241-a08d-2141769abc04 * update ncurses mode bug git-svn-id: svn+ssh://140.110.240.196/partclone_svn@128 93b75dfe-da2d-4241-a08d-2141769abc04 * update po files * update progress.c for i18n * update partclone.c to fix bug at save stdout with ncurses git-svn-id: svn+ssh://140.110.240.196/partclone_svn@127 93b75dfe-da2d-4241-a08d-2141769abc04 2008-04-29 thomas add restore description at gauge git-svn-id: svn+ssh://140.110.240.196/partclone_svn@126 93b75dfe-da2d-4241-a08d-2141769abc04 fix Text User Intereface and add dialog format string. -N --ncurses, Ncurses Interface, but can't save partition data to stdout -X --dialog, output dialog gauge format string, if you want to use dialog mkfifo pipe; (./clone.extfs -d -c -X -s /dev/loop0 2>pipe | cat - > test3_stderr.img) | ./gauge < pipe git-svn-id: svn+ssh://140.110.240.196/partclone_svn@125 93b75dfe-da2d-4241-a08d-2141769abc04 2008-04-28 thomas add TUI mode for partclone. * use ncursesw to display text user interface with i18n support * user interface status * user interface progress bar * configure option --enable-ncursesw for TUI mode Using -X or --tui to display text user interface like ex. clone.extfs -d -c -X -s /dev/loop0 -o test.img git-svn-id: svn+ssh://140.110.240.196/partclone_svn@124 93b75dfe-da2d-4241-a08d-2141769abc04 2008-04-22 thomas keep fixing TUI mode. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@123 93b75dfe-da2d-4241-a08d-2141769abc04 update FS check, use strcmp to replace memcmp. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@122 93b75dfe-da2d-4241-a08d-2141769abc04 2008-04-22 c00jhs00 changelog for version 0.0.6-4. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@121 93b75dfe-da2d-4241-a08d-2141769abc04 2008-04-22 thomas add ifdef for tui mode git-svn-id: svn+ssh://140.110.240.196/partclone_svn@120 93b75dfe-da2d-4241-a08d-2141769abc04 fix last change for log_level only. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@119 93b75dfe-da2d-4241-a08d-2141769abc04 update memcmp size. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@118 93b75dfe-da2d-4241-a08d-2141769abc04 2008-04-21 thomas update Changelog git-svn-id: svn+ssh://140.110.240.196/partclone_svn@117 93b75dfe-da2d-4241-a08d-2141769abc04 try to add new function for #14 "TUI of status reports" add --enable-ncurses to enable TUI and check libncurses add add new option to use TUI, ex: -X or --tui add function open_tui to open text window close_tui to close window TUI_progress_update to show status The option(TUI) is unstable. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@116 93b75dfe-da2d-4241-a08d-2141769abc04 2008-04-21 jazz git-svn-id: svn+ssh://140.110.240.196/partclone_svn@115 93b75dfe-da2d-4241-a08d-2141769abc04 2008-02-21 c00jhs00 Version now is 0.0.6 git-svn-id: svn+ssh://140.110.240.196/partclone_svn@114 93b75dfe-da2d-4241-a08d-2141769abc04 2008-02-20 c00jhs00 clone.fat was not compiled. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@113 93b75dfe-da2d-4241-a08d-2141769abc04 updated for 0.0.6-1 git-svn-id: svn+ssh://140.110.240.196/partclone_svn@112 93b75dfe-da2d-4241-a08d-2141769abc04 2008-02-18 thomas add manual for clone.fat git-svn-id: svn+ssh://140.110.240.196/partclone_svn@111 93b75dfe-da2d-4241-a08d-2141769abc04 Unstable version. add new filesystem: FAT16/32 add --enable-fat to compile clone.fat. add --enable-all to compile all supported filesystem utilities. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@110 93b75dfe-da2d-4241-a08d-2141769abc04 2008-02-16 c00jhs00 changelog updated for 0.0.5-16 git-svn-id: svn+ssh://140.110.240.196/partclone_svn@109 93b75dfe-da2d-4241-a08d-2141769abc04 2008-02-12 thomas fix #28, get right partition size when running partition to partition clone. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@108 93b75dfe-da2d-4241-a08d-2141769abc04 2008-02-10 c00jhs00 Typo checkinh was fixed as checking. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@107 93b75dfe-da2d-4241-a08d-2141769abc04 2008-02-04 c00jhs00 "," was added between partclone.sf.net and partclone.nchc.org.tw git-svn-id: svn+ssh://140.110.240.196/partclone_svn@106 93b75dfe-da2d-4241-a08d-2141769abc04 version automatically updated by svn. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@105 93b75dfe-da2d-4241-a08d-2141769abc04 # partclone.nchc.org.tw was put without http:// in usage. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@104 93b75dfe-da2d-4241-a08d-2141769abc04 http://partclone.nchc.org.tw was added in usage. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@103 93b75dfe-da2d-4241-a08d-2141769abc04 Update the output messages when clone is finished git-svn-id: svn+ssh://140.110.240.196/partclone_svn@102 93b75dfe-da2d-4241-a08d-2141769abc04 2008-01-31 thomas fix about device size use BLKGETSIZE64 to get large partition size fix seek error stop when seek error git-svn-id: svn+ssh://140.110.240.196/partclone_svn@101 93b75dfe-da2d-4241-a08d-2141769abc04 2008-01-31 c00jhs00 updated automatically. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@100 93b75dfe-da2d-4241-a08d-2141769abc04 2008-01-30 c00jhs00 Changelog updted for 0.0.5-13 git-svn-id: svn+ssh://140.110.240.196/partclone_svn@99 93b75dfe-da2d-4241-a08d-2141769abc04 2008-01-30 thomas * reduce seek time * fix number of Ave.Rate * check every filesystem's image_head data... * add new option to disable device and free space checking git-svn-id: svn+ssh://140.110.240.196/partclone_svn@98 93b75dfe-da2d-4241-a08d-2141769abc04 update last fix git-svn-id: svn+ssh://140.110.240.196/partclone_svn@97 93b75dfe-da2d-4241-a08d-2141769abc04 2008-01-30 c00jhs00 Changelog updated for 0.0.5-12. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@96 93b75dfe-da2d-4241-a08d-2141769abc04 2008-01-30 thomas fix stats info git-svn-id: svn+ssh://140.110.240.196/partclone_svn@95 93b75dfe-da2d-4241-a08d-2141769abc04 try to fix long seeking time problem. not test git-svn-id: svn+ssh://140.110.240.196/partclone_svn@94 93b75dfe-da2d-4241-a08d-2141769abc04 fix a bug at clone hfsp get wrong device size git-svn-id: svn+ssh://140.110.240.196/partclone_svn@93 93b75dfe-da2d-4241-a08d-2141769abc04 2008-01-29 c00jhs00 changelog udpated for 0.0.5-11. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@92 93b75dfe-da2d-4241-a08d-2141769abc04 2008-01-29 thomas fix bug to get right destination partition size which bigger than 78GB. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@91 93b75dfe-da2d-4241-a08d-2141769abc04 2008-01-24 c00jhs00 Format the output: Syncing ...OK -> Syncing... OK Rate:%6.2MB/min -> Rate: %6.2MB/min git-svn-id: svn+ssh://140.110.240.196/partclone_svn@90 93b75dfe-da2d-4241-a08d-2141769abc04 2008-01-23 c00jhs00 updated for 0.0.5-10. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@89 93b75dfe-da2d-4241-a08d-2141769abc04 2008-01-23 thomas add function to check memory size. function "check_mem" can make sure you have enough memory and report how many size partclone needed if there is no enough size. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@88 93b75dfe-da2d-4241-a08d-2141769abc04 2008-01-22 thomas fix real size of MB. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@87 93b75dfe-da2d-4241-a08d-2141769abc04 add function "check_free_space" to make sure the free space is enough to save image file. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@86 93b75dfe-da2d-4241-a08d-2141769abc04 Changeset 84 and 85 * set debug level, set -dX or --debug=X. X = 0 is no debug X = 1 is normal debug X = 2 is large log messgae * update log_mesg for different debug level. * add new function "print_option" to print options and argument at debug=1. * configure --enable-all to enable alll supported file systems. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@85 93b75dfe-da2d-4241-a08d-2141769abc04 2008-01-21 thomas update debug message mode but not finish. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@84 93b75dfe-da2d-4241-a08d-2141769abc04 fix #24 git-svn-id: svn+ssh://140.110.240.196/partclone_svn@83 93b75dfe-da2d-4241-a08d-2141769abc04 fix #24, Remove extra space. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@82 93b75dfe-da2d-4241-a08d-2141769abc04 2008-01-20 c00jhs00 Updated for 0.0.5-9. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@81 93b75dfe-da2d-4241-a08d-2141769abc04 2008-01-16 thomas UNSTALBE feature, support device to device. clone.reiserfs -b -s /dev/sda1 -o /dev/sdb1 clone.reiserfs --dd-mode --source /dev/sda1 --output /dev/sdb1 git-svn-id: svn+ssh://140.110.240.196/partclone_svn@80 93b75dfe-da2d-4241-a08d-2141769abc04 2008-01-15 thomas updat atoobox and makefile.am to update ChangeLog every "make dist" automatically. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@79 93b75dfe-da2d-4241-a08d-2141769abc04 add log mesg for bitmap. update svn version string at print_image_ info. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@78 93b75dfe-da2d-4241-a08d-2141769abc04 add new function rescue_sector like ntfsclone to backup bad blocks. clone.ext3 -d -c -R -s /dev/hda1 -o hda1.img clone.ext3 --clone --rescue --source /dev/hda1 --output hda1.img git-svn-id: svn+ssh://140.110.240.196/partclone_svn@77 93b75dfe-da2d-4241-a08d-2141769abc04 2008-01-14 thomas add file toolbox, src/version.c for svn version string git-svn-id: svn+ssh://140.110.240.196/partclone_svn@76 93b75dfe-da2d-4241-a08d-2141769abc04 fix svn string git-svn-id: svn+ssh://140.110.240.196/partclone_svn@75 93b75dfe-da2d-4241-a08d-2141769abc04 translation zh-TW.po fix SVN Revision string git-svn-id: svn+ssh://140.110.240.196/partclone_svn@74 93b75dfe-da2d-4241-a08d-2141769abc04 import GNU-Style Changelog from svn. svn2cl --reparagraph --break-before-msg=2 The tool svn2cl is part of subversion-tools. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@73 93b75dfe-da2d-4241-a08d-2141769abc04 check output exist, and add option --overwrite to replace its content. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@72 93b75dfe-da2d-4241-a08d-2141769abc04 add check_mount to check device is mounted or not before clone/restore. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@71 93b75dfe-da2d-4241-a08d-2141769abc04 fix log mesg when clone/restore extfs, too many log message. fix status information format when "clone.xxx | clone.xxx" git-svn-id: svn+ssh://140.110.240.196/partclone_svn@70 93b75dfe-da2d-4241-a08d-2141769abc04 2008-01-11 c00jhs00 changelog updated. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@69 93b75dfe-da2d-4241-a08d-2141769abc04 2008-01-10 thomas update #18, add finish message git-svn-id: svn+ssh://140.110.240.196/partclone_svn@68 93b75dfe-da2d-4241-a08d-2141769abc04 2008-01-09 c00jhs00 changelog updated for minor changes. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@67 93b75dfe-da2d-4241-a08d-2141769abc04 2008-01-09 thomas update #18 again again again... git-svn-id: svn+ssh://140.110.240.196/partclone_svn@66 93b75dfe-da2d-4241-a08d-2141769abc04 add translation for "Remaining" git-svn-id: svn+ssh://140.110.240.196/partclone_svn@65 93b75dfe-da2d-4241-a08d-2141769abc04 update #18, make sure report information ignore seek time. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@64 93b75dfe-da2d-4241-a08d-2141769abc04 fix and test revision git-svn-id: svn+ssh://140.110.240.196/partclone_svn@63 93b75dfe-da2d-4241-a08d-2141769abc04 2008-01-09 c00jhs00 changelog updated. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@62 93b75dfe-da2d-4241-a08d-2141769abc04 2008-01-08 thomas update #18, change the status format to Elapsed: 00:00:07, Remained: 00:00:00, Completed: 99.84%, Rate: 287.9MB/min, Total Time : 00:00:09, Ave. Rate: 180.0MB/min, 100.00% completed! git-svn-id: svn+ssh://140.110.240.196/partclone_svn@61 93b75dfe-da2d-4241-a08d-2141769abc04 2008-01-08 c00jhs00 changelog updated for ticket #18. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@60 93b75dfe-da2d-4241-a08d-2141769abc04 2008-01-08 thomas update #18, change the status format to Elapsed: 00:00:33, Remained: 00:00:00, Completed: 99.74%, Rate: 4.36MB/s Total Time : 00:00:34, 100.00% completed! git-svn-id: svn+ssh://140.110.240.196/partclone_svn@59 93b75dfe-da2d-4241-a08d-2141769abc04 fix #18:Add a saving/restoring rate and estimated time in the status report like this: ..... Used block count: 35192 99.74% completed, Total: 00040 sec., Estimated: 00000 sec., 3.59 MB/s 100.00% completed Syncing ... git-svn-id: svn+ssh://140.110.240.196/partclone_svn@58 93b75dfe-da2d-4241-a08d-2141769abc04 2008-01-07 c00jhs00 update changelog for 0.0.5-4 git-svn-id: svn+ssh://140.110.240.196/partclone_svn@57 93b75dfe-da2d-4241-a08d-2141769abc04 2008-01-07 thomas fix #15, sync after save/restore. update root-check before open any device or image. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@56 93b75dfe-da2d-4241-a08d-2141769abc04 fux #12, #13 and #17. #13, #17 update as: Partclone v0.0.5 ($Rev: 50 $) http://partclone.sourceforge.net //#17 Starting clone device (/dev/loop0) to image (-) File system: HFS Plus //#13 Device size: 269 MB Space in use: 17 MB Block size: 4096 Byte Used block count: 3976 100.00 percent completed #12, change the error mesg, read from stdin when clone. write to stdout when restore. clone.hfsp -r -s /dev/loop0 Partclone can't restore to stdout. For help,type: clone.hfsplus -h git-svn-id: svn+ssh://140.110.240.196/partclone_svn@55 93b75dfe-da2d-4241-a08d-2141769abc04 2008-01-06 c00jhs00 * Static linking was disabled in debian/rules. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@54 93b75dfe-da2d-4241-a08d-2141769abc04 2008-01-04 c00jhs00 updated for 0.0.5-2 git-svn-id: svn+ssh://140.110.240.196/partclone_svn@53 93b75dfe-da2d-4241-a08d-2141769abc04 Description is updated. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@52 93b75dfe-da2d-4241-a08d-2141769abc04 2008-01-04 jazz * motion6 folder is only for showing how `svn import' work. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@51 93b75dfe-da2d-4241-a08d-2141769abc04 * modified src/Makefile.am : [Bugfix] ticket #8 - linking issue of tarbal and dpkg-buildpackage [Note] `make install' will use related path instead of real path * modified src/partclone.c - add SVN Revision message to usage() * modified debian/[control rules] - add project URL and some detail change for debian packaging git-svn-id: svn+ssh://140.110.240.196/partclone_svn@50 93b75dfe-da2d-4241-a08d-2141769abc04 2008-01-04 thomas fix Ticket #11 Unable to run autoreconf in Debian etch git-svn-id: svn+ssh://140.110.240.196/partclone_svn@49 93b75dfe-da2d-4241-a08d-2141769abc04 2008-01-04 jazz * change release version from 0.0.4 to 0.0.5 * [bugfix] reopen and cloes ticket #8 - modified Makefile.am to fix linking permission problem while using `dpkg-buildpackage -rfakeroot' git-svn-id: svn+ssh://140.110.240.196/partclone_svn@48 93b75dfe-da2d-4241-a08d-2141769abc04 2008-01-04 thomas fix link problem. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@47 93b75dfe-da2d-4241-a08d-2141769abc04 2008-01-04 c00jhs00 updated for new release. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@46 93b75dfe-da2d-4241-a08d-2141769abc04 2008-01-04 thomas fix Ticket #8, making install partclone, those symbolic link files can be automatically linked. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@45 93b75dfe-da2d-4241-a08d-2141769abc04 2008-01-03 jazz * Initial veriosn of motion6 git-svn-id: svn+ssh://140.110.240.196/partclone_svn@44 93b75dfe-da2d-4241-a08d-2141769abc04 * clean up repositories of tags and branches which created by cvs2svn git-svn-id: svn+ssh://140.110.240.196/partclone_svn@43 93b75dfe-da2d-4241-a08d-2141769abc04 * change repository name from trunk to partclone git-svn-id: svn+ssh://140.110.240.196/partclone_svn@42 93b75dfe-da2d-4241-a08d-2141769abc04 2008-01-03 thomas add print version information at --help. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@41 93b75dfe-da2d-4241-a08d-2141769abc04 check stdin/stdout User can't clone from stdin or restore to stdout. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@40 93b75dfe-da2d-4241-a08d-2141769abc04 add image version control. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@39 93b75dfe-da2d-4241-a08d-2141769abc04 add crc check function to avoid data I/O error. reference libcrc which mainatined by Lammert Bies 1999-2007 http://www.lammertbies.nl/comm/info/nl_crc-calculation.html git-svn-id: svn+ssh://140.110.240.196/partclone_svn@38 93b75dfe-da2d-4241-a08d-2141769abc04 add default source is -/stdin. default target is -/stdout. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@37 93b75dfe-da2d-4241-a08d-2141769abc04 fix the ticke about "The better informatio at clone/restore" git-svn-id: svn+ssh://140.110.240.196/partclone_svn@36 93b75dfe-da2d-4241-a08d-2141769abc04 update zh_tw.gmo git-svn-id: svn+ssh://140.110.240.196/partclone_svn@35 93b75dfe-da2d-4241-a08d-2141769abc04 Change Image metadata format! add filesystem information in image_head add buff[4096] in image_head for use in the future. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@34 93b75dfe-da2d-4241-a08d-2141769abc04 2008-01-02 jazz * These template files is not necessary for current packaging usage. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@33 93b75dfe-da2d-4241-a08d-2141769abc04 2008-01-02 thomas add infoclone.c to print Image file information. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@32 93b75dfe-da2d-4241-a08d-2141769abc04 2008-01-02 jazz * modified debian/[control, changelog, rules] - to build debian package with static linking binary as default * update src/Makefile.in - if user did not install automake and autoconf then Makefile.am will not update Makefile.in automatically, so we put it in the version control repository. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@31 93b75dfe-da2d-4241-a08d-2141769abc04 * [BUGFIX][BUG #1] fixed linking time error while enabling support of xfs. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@30 93b75dfe-da2d-4241-a08d-2141769abc04 2008-01-02 thomas add function check_size to check dest partition size. make sure the size is enough. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@29 93b75dfe-da2d-4241-a08d-2141769abc04 fix a bug in partclone.c. to make sure it return the I/O size. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@28 93b75dfe-da2d-4241-a08d-2141769abc04 check I/O syncronization while using pipe and stdin I use read_all and write_all to replace read and write. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@27 93b75dfe-da2d-4241-a08d-2141769abc04 2008-01-02 jazz add ToDo List: I/O syncronization git-svn-id: svn+ssh://140.110.240.196/partclone_svn@26 93b75dfe-da2d-4241-a08d-2141769abc04 add ToDo list: checksum git-svn-id: svn+ssh://140.110.240.196/partclone_svn@25 93b75dfe-da2d-4241-a08d-2141769abc04 update ToDo List: new bug #1 git-svn-id: svn+ssh://140.110.240.196/partclone_svn@24 93b75dfe-da2d-4241-a08d-2141769abc04 add ToDo List git-svn-id: svn+ssh://140.110.240.196/partclone_svn@23 93b75dfe-da2d-4241-a08d-2141769abc04 2008-01-02 thomas add more information about the size, xxx MB, xxx Byte... update zh_tw.po git-svn-id: svn+ssh://140.110.240.196/partclone_svn@22 93b75dfe-da2d-4241-a08d-2141769abc04 2008-01-01 c00jhs00 ... git-svn-id: svn+ssh://140.110.240.196/partclone_svn@21 93b75dfe-da2d-4241-a08d-2141769abc04 add % for status report. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@20 93b75dfe-da2d-4241-a08d-2141769abc04 ... git-svn-id: svn+ssh://140.110.240.196/partclone_svn@19 93b75dfe-da2d-4241-a08d-2141769abc04 2008-01-01 jazz * fix pipe syncronization problem - reference from ntfsclone.c io_all() function git-svn-id: svn+ssh://140.110.240.196/partclone_svn@18 93b75dfe-da2d-4241-a08d-2141769abc04 2008-01-01 c00jhs00 ... git-svn-id: svn+ssh://140.110.240.196/partclone_svn@17 93b75dfe-da2d-4241-a08d-2141769abc04 Update the descriptions in help. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@16 93b75dfe-da2d-4241-a08d-2141769abc04 2007-12-31 jazz * modified configure.ac and src/Makefile.am to add support to compile static linking programs * Makefile.in, configure and src/Makefile.in are modified by autoreconf git-svn-id: svn+ssh://140.110.240.196/partclone_svn@15 93b75dfe-da2d-4241-a08d-2141769abc04 2007-12-31 c00jhs00 spec for rpm package. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@14 93b75dfe-da2d-4241-a08d-2141769abc04 2007-12-31 jazz testing http://free.nchc.org.tw/cvs2rss.php git-svn-id: svn+ssh://140.110.240.196/partclone_svn@13 93b75dfe-da2d-4241-a08d-2141769abc04 2007-12-13 thomas dd files for debian git-svn-id: svn+ssh://140.110.240.196/partclone_svn@12 93b75dfe-da2d-4241-a08d-2141769abc04 add debian for make debian package git-svn-id: svn+ssh://140.110.240.196/partclone_svn@11 93b75dfe-da2d-4241-a08d-2141769abc04 2007-12-10 c00jhs00 ... git-svn-id: svn+ssh://140.110.240.196/partclone_svn@10 93b75dfe-da2d-4241-a08d-2141769abc04 2007-11-26 thomas fix stdout/stdin bug git-svn-id: svn+ssh://140.110.240.196/partclone_svn@9 93b75dfe-da2d-4241-a08d-2141769abc04 fix no --debug error make partclone always open log file git-svn-id: svn+ssh://140.110.240.196/partclone_svn@8 93b75dfe-da2d-4241-a08d-2141769abc04 fix large file support and hfsp get free bitmap error git-svn-id: svn+ssh://140.110.240.196/partclone_svn@7 93b75dfe-da2d-4241-a08d-2141769abc04 default not enable reiserfs, until progsreiserfs can get from debian git-svn-id: svn+ssh://140.110.240.196/partclone_svn@6 93b75dfe-da2d-4241-a08d-2141769abc04 2007-11-25 (no author) <(no author)@93b75dfe-da2d-4241-a08d-2141769abc04> This commit was manufactured by cvs2svn to create tag 'r_0_1'. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@5 93b75dfe-da2d-4241-a08d-2141769abc04 2007-11-25 thomas initial partclone 2007 git-svn-id: svn+ssh://140.110.240.196/partclone_svn@4 93b75dfe-da2d-4241-a08d-2141769abc04 2007-11-25 (no author) <(no author)@93b75dfe-da2d-4241-a08d-2141769abc04> This commit was manufactured by cvs2svn to create branch 'thomas'. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@3 93b75dfe-da2d-4241-a08d-2141769abc04 2007-11-25 thomas Initial revision git-svn-id: svn+ssh://140.110.240.196/partclone_svn@2 93b75dfe-da2d-4241-a08d-2141769abc04 2007-11-25 (no author) <(no author)@93b75dfe-da2d-4241-a08d-2141769abc04> New repository initialized by cvs2svn. git-svn-id: svn+ssh://140.110.240.196/partclone_svn@1 93b75dfe-da2d-4241-a08d-2141769abc04 partclone-0.2.86/INSTALL000066400000000000000000000011431262102574200146270ustar00rootroot00000000000000#required library e2fsprogs (official library) ntfs3g | ntfsprogs (official library) libreiserfs (official library) btrfs-tools (build-in) hfs plus (build-in) fat (build-in) reiserfs4progs (patched library, not in debian) vmfs-tools (patched library, not in debian) ufs (patched library, not in debian) jfs (patched library, not in debian) xfs (patched library, not in debian) #check patched library here: http://free.nchc.org.tw/drbl-core/pool/drbl/dev/ # Installation autoreconf # optional ./configure --enabel-ncursesw --enable-all make sudo make install please access partclone.org for more information partclone-0.2.86/Makefile.am000066400000000000000000000004071262102574200156340ustar00rootroot00000000000000AUTOMAKE_OPTIONS = subdir-objects SUBDIRS= po src docs tests fail-mbr ACLOCAL_AMFLAGS = -I m4 EXTRA_DIST = m4/ChangeLog config.rpath toolbox src/deplib_version.c src/version.h src/ufs debian ChangeLog: FORCE srcdir=. $(SHELL) ./toolbox --update-log FORCE: partclone-0.2.86/Makefile.in000066400000000000000000000621331262102574200156510ustar00rootroot00000000000000# Makefile.in generated by automake 1.15 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2014 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = . ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/gettext.m4 \ $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \ $(am__configure_deps) $(am__DIST_COMMON) am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ configure.lineno config.status.lineno mkinstalldirs = $(install_sh) -d CONFIG_HEADER = config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ cscope distdir dist dist-all distcheck am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) \ $(LISP)config.h.in # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags CSCOPE = cscope DIST_SUBDIRS = $(SUBDIRS) am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/config.h.in \ ABOUT-NLS AUTHORS COPYING ChangeLog INSTALL NEWS TODO compile \ config.guess config.rpath config.sub depcomp install-sh \ missing DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) distdir = $(PACKAGE)-$(VERSION) top_distdir = $(distdir) am__remove_distdir = \ if test -d "$(distdir)"; then \ find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ && rm -rf "$(distdir)" \ || { sleep 5 && rm -rf "$(distdir)"; }; \ else :; fi am__post_remove_distdir = $(am__remove_distdir) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" DIST_ARCHIVES = $(distdir).tar.gz GZIP_ENV = --best DIST_TARGETS = dist-gzip distuninstallcheck_listfiles = find . -type f -print am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \ | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$' distcleancheck_listfiles = find . -type f -print ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXT2FS_CFLAGS = @EXT2FS_CFLAGS@ EXT2FS_LIBS = @EXT2FS_LIBS@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ LDFLAGS = @LDFLAGS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LN_S = @LN_S@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ NTFS_CFLAGS = @NTFS_CFLAGS@ NTFS_LIBS = @NTFS_LIBS@ OBJEXT = @OBJEXT@ ORIGINAL_CFLAGS = @ORIGINAL_CFLAGS@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ POSUB = @POSUB@ RM = @RM@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ USE_NLS = @USE_NLS@ UUID_CFLAGS = @UUID_CFLAGS@ UUID_LIBS = @UUID_LIBS@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = subdir-objects SUBDIRS = po src docs tests fail-mbr ACLOCAL_AMFLAGS = -I m4 EXTRA_DIST = m4/ChangeLog config.rpath toolbox src/deplib_version.c src/version.h src/ufs debian all: config.h $(MAKE) $(AM_MAKEFLAGS) all-recursive .SUFFIXES: am--refresh: Makefile @: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \ $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ echo ' $(SHELL) ./config.status'; \ $(SHELL) ./config.status;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) $(SHELL) ./config.status --recheck $(top_srcdir)/configure: $(am__configure_deps) $(am__cd) $(srcdir) && $(AUTOCONF) $(ACLOCAL_M4): $(am__aclocal_m4_deps) $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) $(am__aclocal_m4_deps): config.h: stamp-h1 @test -f $@ || rm -f stamp-h1 @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1 stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status @rm -f stamp-h1 cd $(top_builddir) && $(SHELL) ./config.status config.h $(srcdir)/config.h.in: $(am__configure_deps) ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) rm -f stamp-h1 touch $@ distclean-hdr: -rm -f config.h stamp-h1 # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscope: cscope.files test ! -s cscope.files \ || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS) clean-cscope: -rm -f cscope.files cscope.files: clean-cscope cscopelist cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags -rm -f cscope.out cscope.in.out cscope.po.out cscope.files distdir: $(DISTFILES) $(am__remove_distdir) test -d "$(distdir)" || mkdir "$(distdir)" @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done -test -n "$(am__skip_mode_fix)" \ || find "$(distdir)" -type d ! -perm -755 \ -exec chmod u+rwx,go+rx {} \; -o \ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ || chmod -R a+r "$(distdir)" dist-gzip: distdir tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz $(am__post_remove_distdir) dist-bzip2: distdir tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2 $(am__post_remove_distdir) dist-lzip: distdir tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz $(am__post_remove_distdir) dist-xz: distdir tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz $(am__post_remove_distdir) dist-tarZ: distdir @echo WARNING: "Support for distribution archives compressed with" \ "legacy program 'compress' is deprecated." >&2 @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z $(am__post_remove_distdir) dist-shar: distdir @echo WARNING: "Support for shar distribution archives is" \ "deprecated." >&2 @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz $(am__post_remove_distdir) dist-zip: distdir -rm -f $(distdir).zip zip -rq $(distdir).zip $(distdir) $(am__post_remove_distdir) dist dist-all: $(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:' $(am__post_remove_distdir) # This target untars the dist file and tries a VPATH configuration. Then # it guarantees that the distribution is self-contained by making another # tarfile. distcheck: dist case '$(DIST_ARCHIVES)' in \ *.tar.gz*) \ GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\ *.tar.bz2*) \ bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ *.tar.lz*) \ lzip -dc $(distdir).tar.lz | $(am__untar) ;;\ *.tar.xz*) \ xz -dc $(distdir).tar.xz | $(am__untar) ;;\ *.tar.Z*) \ uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ *.shar.gz*) \ GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\ *.zip*) \ unzip $(distdir).zip ;;\ esac chmod -R a-w $(distdir) chmod u+w $(distdir) mkdir $(distdir)/_build $(distdir)/_build/sub $(distdir)/_inst chmod a-w $(distdir) test -d $(distdir)/_build || exit 0; \ dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ && am__cwd=`pwd` \ && $(am__cd) $(distdir)/_build/sub \ && ../../configure \ $(AM_DISTCHECK_CONFIGURE_FLAGS) \ $(DISTCHECK_CONFIGURE_FLAGS) \ --srcdir=../.. --prefix="$$dc_install_base" \ && $(MAKE) $(AM_MAKEFLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) dvi \ && $(MAKE) $(AM_MAKEFLAGS) check \ && $(MAKE) $(AM_MAKEFLAGS) install \ && $(MAKE) $(AM_MAKEFLAGS) installcheck \ && $(MAKE) $(AM_MAKEFLAGS) uninstall \ && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ distuninstallcheck \ && chmod -R a-w "$$dc_install_base" \ && ({ \ (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ } || { rm -rf "$$dc_destdir"; exit 1; }) \ && rm -rf "$$dc_destdir" \ && $(MAKE) $(AM_MAKEFLAGS) dist \ && rm -rf $(DIST_ARCHIVES) \ && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ && cd "$$am__cwd" \ || exit 1 $(am__post_remove_distdir) @(echo "$(distdir) archives ready for distribution: "; \ list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' distuninstallcheck: @test -n '$(distuninstallcheck_dir)' || { \ echo 'ERROR: trying to run $@ with an empty' \ '$$(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ $(am__cd) '$(distuninstallcheck_dir)' || { \ echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left after uninstall:" ; \ if test -n "$(DESTDIR)"; then \ echo " (check DESTDIR support)"; \ fi ; \ $(distuninstallcheck_listfiles) ; \ exit 1; } >&2 distcleancheck: distclean @if test '$(srcdir)' = . ; then \ echo "ERROR: distcleancheck can only run from a VPATH build" ; \ exit 1 ; \ fi @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left in build directory after distclean:" ; \ $(distcleancheck_listfiles) ; \ exit 1; } >&2 check-am: all-am check: check-recursive all-am: Makefile config.h installdirs: installdirs-recursive installdirs-am: install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-recursive clean-am: clean-generic mostlyclean-am distclean: distclean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -f Makefile distclean-am: clean-am distclean-generic distclean-hdr distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -rf $(top_srcdir)/autom4te.cache -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: .MAKE: $(am__recursive_targets) all install-am install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \ am--refresh check check-am clean clean-cscope clean-generic \ cscope cscopelist-am ctags ctags-am dist dist-all dist-bzip2 \ dist-gzip dist-lzip dist-shar dist-tarZ dist-xz dist-zip \ distcheck distclean distclean-generic distclean-hdr \ distclean-tags distcleancheck distdir distuninstallcheck dvi \ dvi-am html html-am info info-am install install-am \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs installdirs-am \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am .PRECIOUS: Makefile ChangeLog: FORCE srcdir=. $(SHELL) ./toolbox --update-log FORCE: # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: partclone-0.2.86/NEWS000066400000000000000000000000431262102574200142730ustar00rootroot00000000000000pleace access http://partclone.org partclone-0.2.86/README.Packages/000077500000000000000000000000001262102574200162515ustar00rootroot00000000000000partclone-0.2.86/README.Packages/debian.jessie/000077500000000000000000000000001262102574200207545ustar00rootroot00000000000000partclone-0.2.86/README.Packages/debian.jessie/changelog000066400000000000000000000626631262102574200226430ustar00rootroot00000000000000partclone (0.2.71-1) unstable; urgency=medium [ Yu-Chin Tsai ] * Non-maintainer upload. * update release for jessie -- Thomas Tsai Wed, 09 Jul 2014 23:12:03 +0800 partclone (0.2.51) unstable; urgency=low * update makefile * update supported list * update process for elapsed time over 24hr * update version to 0.2.51 * update some docs -- Thomas Tsai Thu, 20 Sep 2012 17:07:41 +0800 partclone (0.2.50) unstable; urgency=low * release 0.2.49 * update control * update control * add partclone.btrfs.8 * add more detail message in image head output * add exfat * update exfat and add exfat man docs * add test for exfat * update test and size information * version 0.2.50 -- Thomas Tsai Tue, 10 Jul 2012 16:39:19 +0800 partclone (0.2.49) unstable; urgency=low * release 0.2.48 * update TODO * minor update readme * update docs * update docs * update manpage * fix quiet mode issue. The issue make partclone can't stop/finish even action is done. bug report from pille -- Thomas Tsai Tue, 10 Jul 2012 16:35:27 +0800 partclone (0.2.48) unstable; urgency=low [ Thomas Tsai ] * update debian control for vmfs-tools [ thomas ] * ignore unallocated block for vmfs [ Thomas Tsai ] * update bitmap progress * A partclone bug found when it backs up WindowsServer2008R2 (64bit) * update vmfs for some unallocated block -- Thomas Tsai Tue, 01 May 2012 11:32:47 +0800 partclone (0.2.47) unstable; urgency=low * try to fix ID: 3509757 from clonezilla track system * change row to raw, noticed from Vincent van Adrighem * update fresh, add sleep in progress thread to reduce cpu usage, contributed and bug information from http://sourceforge.net/tracker/?func=detail&aid=3509757&group_id=115473&atid=671650 * update fresh done * 0.2.47 -- Thomas Tsai Wed, 18 Apr 2012 13:41:31 +0800 partclone (0.2.46) unstable; urgency=low * accept part of patch from Matthew Booth's review * update partclone.vmfs for version 5 * update manpages * update document, some example error. * update vmfsclone to backup vmfs5 well * accept patch from Rommer to update memory usage * and release 0.2.46 -- Thomas Tsai Mon, 02 Apr 2012 09:14:23 +0800 partclone (0.2.45) unstable; urgency=low * print vmfs version from fstype * add compatibility of vmfs3 and vmfs5 -- Thomas Tsai Wed, 18 Jan 2012 10:39:22 +0800 partclone (0.2.44) unstable; urgency=low * update pui for mode dev-to-dev -- Thomas Tsai Tue, 17 Jan 2012 15:11:30 +0800 partclone (0.2.43) unstable; urgency=low * 0.2.43 -- Thomas Tsai Tue, 27 Dec 2011 16:25:57 +0800 partclone (0.2.42) unstable; urgency=low * add option B to disable block detail; old progress style. * add finish progress to dd * 0.2.42 -- Thomas Tsai Tue, 27 Dec 2011 15:58:55 +0800 partclone (0.2.41) unstable; urgency=low * add block status * update progress bar * add thread to display progress, draft * add thread to dd, restore and chkimg * 0.2.41 -- Thomas Tsai Tue, 27 Dec 2011 00:53:41 +0800 partclone (0.2.40) unstable; urgency=low * update progress seeking at 100% -- Thomas Tsai Fri, 23 Dec 2011 10:25:43 +0800 partclone (0.2.39) unstable; urgency=low * 0.2.39 * updaet ntfsfixboot to version 1.0 -- Thomas Tsai Mon, 12 Dec 2011 14:49:22 +0800 partclone (0.2.38) unstable; urgency=low * update for makefile for ncursesw * update for progress * 0.2.38 -- Thomas Tsai Mon, 12 Dec 2011 14:27:23 +0800 partclone (0.2.37) unstable; urgency=low * add -I/usr/include/ncursesw/ * release 0.2.37 -- Thomas Tsai Wed, 23 Nov 2011 16:32:09 +0800 partclone (0.2.36) unstable; urgency=low * update ncurses size * 0.2.36 -- Thomas Tsai Wed, 23 Nov 2011 16:31:06 +0800 partclone (0.2.35) unstable; urgency=low * move debian folder to README.Packages as sample * update control for debian-sid * save last changelog ($version) * update version script * add debian * re remove debian * update TODO * add debian * remove debian * add debian * move partclone.spec to README.Packages/partclone.spec * update * align version and tag * update toolbox -- Thomas Tsai Wed, 02 Nov 2011 01:07:24 +0800 partclone (0.2.34) unstable; urgency=low * update autoconf and automake for squeeze -- Thomas Tsai Tue, 01 Nov 2011 11:32:42 +0800 partclone (0.2.33) unstable; urgency=low * update makefile for ncurses static linking * update memory usage * update ncurses progress bar -- Thomas Tsai Thu, 27 Oct 2011 22:05:17 +0800 partclone (0.2.32) unstable; urgency=low * accept patch file from Rommer. * Attached patch for partclone 0.2.31 reduces memory usage by 4-8 times. by Rommer. -- Thomas Tsai Wed, 12 Oct 2011 21:27:43 +0800 partclone (0.2.31) unstable; urgency=low * update for vmfs5 -- Thomas Tsai Wed, 12 Oct 2011 21:27:43 +0800 partclone (0.2.30) unstable; urgency=low * patch for new vmfs-tools -- Thomas Tsai Tue, 11 Oct 2011 21:21:24 +0800 partclone (0.2.29) unstable; urgency=low * fix bugs * release 0.2.29 -- Thomas Tsai Mon, 12 Sep 2011 21:21:24 +0800 partclone (0.2.28) unstable; urgency=low * update e2fslibs for squeeze * fix bug for ntfsclone with ncurses on unstable -- Thomas Tsai Thu, 08 Sep 2011 22:58:27 +0800 partclone (0.2.27) unstable; urgency=low * accept patch from Georges about configure, fixIntTypes and typos in manpages * try to fix issue for bitmap, suggestion from Paul. -- Thomas Tsai Tue, 30 Aug 2011 11:45:06 +0800 partclone (0.2.26) unstable; urgency=low * update test script -- Thomas Tsai Mon, 15 Aug 2011 10:45:06 +0800 partclone (0.2.25) unstable; urgency=low * update for e2fslibs 1.42~WIP-2011-07-02 * compact ntfs and ntfs-3g -- Thomas Tsai Mon, 15 Aug 2011 10:45:06 +0800 partclone (0.2.24) natty; urgency=low * accept patch from Ian Abbott. * '--domain' (-D) and -offset_domain=X to generate domain file for ddrescue. -- Thomas Tsai Tue, 24 May 2011 10:45:06 +0800 partclone (0.2.23) maverick; urgency=low * update manpages -- Thomas Tsai Fri, 22 Apr 2011 11:02:59 +0800 partclone (0.2.22) maverick; urgency=low * typo error for progress -- Thomas Tsai Mon, 28 Mar 2011 15:19:16 +0800 partclone (0.2.21) maverick; urgency=low * fix bug for partclone.dd and partclone.restore for stdin dd data. -- Thomas Tsai Tue, 22 Mar 2011 14:21:11 +0800 partclone (0.2.20) maverick; urgency=low * fix dd issue. set default size as target size for stdin data. -- Thomas Tsai Mon, 14 Mar 2011 10:12:19 +0800 partclone (0.2.19) unstable; urgency=low * update makefile for btrf -- Thomas Tsai Wed, 09 Mar 2011 14:06:05 +0800 partclone (0.2.18) unstable; urgency=low * add option max_block_cache to get better performance escpcially small block size(fat) * update typo error -- Thomas Tsai Tue, 25 Jan 2011 16:06:05 +0800 partclone (0.2.17) unstable; urgency=low * update for ext4 metadata mismatch issue * update makefile and configure -- Thomas Tsai Tue, 25 Jan 2011 16:06:05 +0800 partclone (0.2.16) unstable; urgency=low * add option --quiet to disable progress bar * add option --restore_row_file to create special file for mounting with loop option -- Thomas Tsai Wed, 06 Oct 2010 16:06:05 +0800 partclone (0.2.15) unstable; urgency=low * Bug fixed: btrfs clone fail, lost some metadata message * Add po: add fr_FR po file from Cédric, very thanks. -- Thomas Tsai Wed, 01 Sep 2010 10:25:48 +0800 partclone (0.2.14) unstable; urgency=low * add btrfs support -- Thomas Tsai Sun, 22 Aug 2010 15:14:20 +0800 partclone (0.2.13) unstable; urgency=low * add link partclone.VMFS_volume_member * fix bug: jfsclone segfault * add debian/control pkg-config -- Thomas Tsai Wed, 28 Jul 2010 17:14:20 +0800 partclone (0.2.12) unstable; urgency=low * New Feature: The jfs filesystem is supported. -- Thomas Tsai Wed, 30 Jun 2010 11:58:41 +0800 partclone (0.2.11) unstable; urgency=low * Bug fixed: xfsclone type error for amd64 * Update control file: add libvmfs -- Thomas Tsai Wed, 19 May 2010 12:22:07 +0800 partclone (0.2.10) unstable; urgency=low * Bug fixed: chkimg.c not work * Bug fixed: new xfsclone -- Thomas Tsai Wed, 19 May 2010 12:22:07 +0800 partclone (0.2.9) unstable; urgency=low * Bug fixed: error for backup partition larger than 8.7T * Bug fixed: better memory usage for restore -- Thomas Tsai Thu, 29 Apr 2010 15:22:07 +0800 partclone (0.2.8) unstable; urgency=low * Bug fixed: update progress bar faster -- Thomas Tsai Mon, 29 Mar 2010 16:22:38 +0800 partclone (0.2.7-1) unstable; urgency=low * fix progress bug about: alwayn new line for 640x480 resolution * update version -- Thomas Tsai Tue, 16 Mar 2010 15:13:04 +0800 partclone (0.2.6-1) unstable; urgency=low * update version -- Thomas Tsai Mon, 15 Mar 2010 11:29:18 +0800 partclone (0.2.5-1) unstable; urgency=low * A bug about 0 rate for bitmap calculation. * update partclone to show more readable size for partition and rate/min. -- Thomas Tsai Fri, 12 Mar 2010 09:15:31 +0800 partclone (0.2.4-1) unstable; urgency=low * autogen git number * fix progress inf bug -- Thomas Tsai Wed, 10 Mar 2010 16:30:55 +0800 partclone (0.2.3-1) unstable; urgency=low * add partclone.fstype to test filesystem type (vmfs only) * update svn versionto git version -- Thomas Tsai Tue, 02 Mar 2010 13:50:26 +0800 partclone (0.2.0-2) unstable; urgency=low * VMFS supported in this release. -- Steven Shiau Sun, 14 Feb 2010 15:00:00 +0800 partclone (0.2.0-1) unstable; urgency=low [ Yu-Chin Tsai ] * A test release. -- Thomas Tsai Wed, 06 Jan 2010 16:07:05 +0800 partclone (0.1.9-5) unstable; urgency=low [ Yu-Chin Tsai ] * A bug about hfsplus error for 2 or more extents was fixed. -- Steven Shiau Wed, 25 Nov 2009 16:54:00 +0800 partclone (0.1.9-4) unstable; urgency=low * update configure.ac, set ufs as default enabled file system. * update progress bar to show the "100%" in the end. -- Yu-Chin Tsai Mon, 16 Nov 2009 14:46:04 +0800 partclone (0.1.9-3) unstable; urgency=low [ Yu-Chin Tsai ] * An option to ignore CRC checking was added. -- Steven Shiau Tue, 03 Nov 2009 17:16:00 +0800 partclone (0.1.9-2) unstable; urgency=low [ Yu-Chin Tsai ] * Bug fixed: update log message and open fail message for ufsclone. Thanks to dswartz for testing ufs backup and report. -- Steven Shiau Fri, 09 Oct 2009 11:14:00 +0800 partclone (0.1.9-1) unstable; urgency=low [ Yu-Chin Tsai ] * Bug fixed: XFS clone failure was fixed. * UFS was added. -- Yu-Chin Tsai Thu, 17 Sep 2009 14:07:33 +0800 partclone (0.1.1-16) unstable; urgency=low [Thomas Tsai] * Bug fixed: FAT clone failure was fixed. -- Steven Shiau Sun, 09 Aug 2009 08:49:00 +0800 partclone (0.1.1-15) unstable; urgency=low [Thomas Tsai] * Bug fixed: Wrong path for exec files. -- Steven Shiau Wed, 24 Jun 2009 16:48:00 +0800 partclone (0.1.1-14) unstable; urgency=low [Thomas Tsai] * Bug fixed: version number from SVN was not shown correctly. -- Steven Shiau Wed, 24 Jun 2009 14:36:00 +0800 partclone (0.1.1-13) unstable; urgency=low [Thomas Tsai] * Prompt messages were updated. -- Steven Shiau Fri, 18 Jun 2009 13:30:00 +0800 partclone (0.1.1-12) unstable; urgency=low [Thomas Tsai] * An option was added: --logfile or -L to specify file for log message. * A new program partclone.chkimg was added to help checking img by CRC. -- Steven Shiau Wed, 17 Jun 2009 10:34:00 +0800 partclone (0.1.1-11) unstable; urgency=low [Thomas Tsai] * update clear_buf * The patch from Kristian Erik Hermansen. fix progress.c:152- SECURITY: fprintf call should have "%s" as argument 1 -- Steven Shiau Sat, 13 Jun 2009 14:39:00 +0800 partclone (0.1.1-10) unstable; urgency=low [Thomas Tsai] * Bug fixed: pointer problem was fixed. * Bug fixed: buffer overflow problem was fixed. Thanks to Kristian Erik Hermansen and Piavlo. * Bug fixed: a bug about hfs+ was fixed. -- Steven Shiau Wed, 10 Jun 2009 10:39:00 +0800 partclone (0.1.1-9) unstable; urgency=low [Steven Shiau] * Some output messages were polished again. -- Steven Shiau Tue, 02 Jun 2009 18:09:00 +0800 partclone (0.1.1-8) unstable; urgency=low [Thomas Tsai] * Some output messages were polished. -- Steven Shiau Tue, 02 Jun 2009 16:51:00 +0800 partclone (0.1.1-7) unstable; urgency=low [Thomas Tsai] * Bug fixed: Progress update with nogui, "Calculating bitmap..." was added without option -d. -- Steven Shiau Mon, 01 Jun 2009 22:36:00 +0800 partclone (0.1.1-6) unstable; urgency=low [Thomas Tsai] * bug of CRC in 64 bit image problem was fixed. A better method will be imlemented in the nexe version of image format. -- Steven Shiau Sat, 30 May 2009 12:10:00 +0800 partclone (0.1.1-5) unstable; urgency=low [Thomas Tsai] * bug of time calculating was fixed. -- Steven Shiau Wed, 27 May 2009 22:13:00 +0800 partclone (0.1.1-4) unstable; urgency=low [Thomas Tsai] * Update default RES from 10000 to 1000. -- Steven Shiau Wed, 27 May 2009 12:59:00 +0800 partclone (0.1.1-3) unstable; urgency=low [Thomas Tsai] * Bug fixed: block device should not have to use "--overwrite". -- Steven Shiau Wed, 27 May 2009 11:23:00 +0800 partclone (0.1.1-2) unstable; urgency=low [Thomas Tsai] * partclone.ntfsreloc is linked to partclone.ntfsfixboot. -- Steven Shiau Fri, 22 May 2009 13:52:00 +0800 partclone (0.1.1-1) unstable; urgency=low [Thomas Tsai] * Minor updates for output messages. * New Feature: add argument to set fresh of progress bar * New Feature: restore to new file(non-block device) * A bug about crc check in 64bit image * Update partclone.ntfsreloc to ntfsfixboot.c from http://cc.jct.ac.il/~shaneh/ntfsfixboot.c -- root Fri, 22 May 2009 05:52:00 +0800 partclone (0.1.0-10) unstable; urgency=low [ Thomas Tsai ] * Bug fixed: clonezilla-Bugs-2784676. Thanks to njorl _at_ users sourceforge net. -- Steven Shiau Fri, 01 May 2009 10:55:00 +0800 partclone (0.1.0-9) unstable; urgency=low [ Steven Shiau ] * Minor updates for output messages. -- Steven Shiau Sun, 26 Apr 2009 13:54:00 +0800 partclone (0.1.0-8) unstable; urgency=low [ Steven Shiau ] * Minor updates for output messages. [ Thomas Tsai ] * EXECNAME was added for partclone.restore. -- Steven Shiau Fri, 24 Apr 2009 14:07:00 +0800 partclone (0.1.0-7) unstable; urgency=low [ Thomas Tsai ] * partclone.ext4dev is linkded now. -- Steven Shiau Thu, 23 Apr 2009 19:01:00 +0800 partclone (0.1.0-6) unstable; urgency=low [ Thomas Tsai ] * A bug about partclone.restore used to restore known file systems was fixed. -- Steven Shiau Thu, 18 Apr 2009 09:59:00 +0800 partclone (0.1.0-5) unstable; urgency=low [ Thomas Tsai ] * A bug about checking partition size was fixed. -- Steven Shiau Thu, 16 Apr 2009 15:03:00 +0800 partclone (0.1.0-4) unstable; urgency=low [ Thomas Tsai ] * Local device to device copy mode option "-b, --dd-mode" was changed to be "-b, --dev-to-dev" * A bug about partclone.dd wrongly get the partition size was fixed. -- Steven Shiau Thu, 16 Apr 2009 12:16:00 +0800 partclone (0.1.0-3) unstable; urgency=low [ Thomas Tsai ] * Bug fixed: partclone.ntfs statistics data was wrong when doing partition to partition clone. -- Steven Shiau Tue, 15 Apr 2009 10:52:00 +0800 partclone (0.1.0-2) unstable; urgency=low [ Steven Shiau ] * --enable-static is on again. -- Steven Shiau Tue, 10 Apr 2009 11:47:00 +0800 partclone (0.1.0-1) unstable; urgency=low [ Thomas Tsai ] * partclone.ext4, partclone.dd, partclone.restore were added. -- Steven Shiau Tue, 07 Apr 2009 15:01:00 +0800 partclone (0.0.9-4) unstable; urgency=low [ Thomas Tsai ] * A bug about FAT12 was fixed. -- Steven Shiau Tue, 30 Dec 2008 13:41:00 +0800 partclone (0.0.9-3) unstable; urgency=low [ Steven Shiau ] * New upstream ntfsreloc.c 0.8. -- Steven Shiau Thu, 25 Dec 2008 15:32:00 +0800 partclone (0.0.9-2) unstable; urgency=low [ Thomas Tsai ] * Update dirty message for ntfsclone-ng. * Check filesystem before cloning partition. Partclone will make sure that. * Add check hfs_plus filesystem before cloning volume. * Update fatclone.c fatclone.h clearly. update dirty message for extfs. -- Steven Shiau Mon, 22 Dec 2008 09:46:00 +0800 partclone (0.0.9-1) unstable; urgency=low # New features: partclone.ntfsreloc and partclone.ntfs were added. -- Steven Shiau Thu, 30 Oct 2008 10:51:00 +0800 partclone (0.0.8-8) unstable; urgency=low # Bug fixed: Failing to restore fat32 image was fixed by Thomas Tsai. -- Steven Shiau Wed, 30 Jul 2008 09:18:00 +0800 partclone (0.0.8-7) unstable; urgency=low # partclone.hfsplus link was added by Thomas Tsai. -- Steven Shiau Thu, 24 Jul 2008 11:53:00 +0800 partclone (0.0.8-6) unstable; urgency=low # Bug fixed: partclone.fat12 link was not done. -- Steven Shiau Fri, 11 Jul 2008 16:11:00 +0800 partclone (0.0.8-5) unstable; urgency=low # fat12 was added by Thomas Tsai. -- Steven Shiau Fri, 11 Jul 2008 15:03:00 +0800 partclone (0.0.8-4) unstable; urgency=low # Enable static linking. -- Steven Shiau Sat, 28 Jun 2008 10:22:00 +0800 partclone (0.0.8-3) unstable; urgency=low # Some minor updates about messages by Thomas Tsai. -- Steven Shiau Sun, 15 Jun 2008 22:48:00 +0800 partclone (0.0.8-2) unstable; urgency=low # configure.ac updated by Thomas Tsai. # partclone website is www.partclone.org now. -- Steven Shiau Mon, 26 May 2008 14:19:00 +0800 partclone (0.0.8-1) unstable; urgency=low # clone.$FS was renamed as partclone.$FS by Thomas Tsai. -- Steven Shiau Sun, 25 May 2008 09:19:00 +0800 partclone (0.0.7-4) unstable; urgency=low # Some bugs about ncursesw were fixed by Thomas Tsai. -- Steven Shiau Fri, 16 May 2008 16:18:00 +0800 partclone (0.0.7-3) unstable; urgency=low # Some bugs about ncursesw were fixed by Thomas Tsai. -- Steven Shiau Thu, 06 May 2008 23:00:00 +0800 partclone (0.0.7-2) unstable; urgency=low # Use --enable-ncursesw by default. -- Steven Shiau Thu, 01 May 2008 11:13:00 +0800 partclone (0.0.7-1) unstable; urgency=low # New functions: TUI mode for output done by Thomas Tsai. -- Steven Shiau Thu, 01 May 2008 11:08:00 +0800 partclone (0.0.6-4) unstable; urgency=low # Some new function for #14 "TUI of status reports" from Thomas Tsai. # Smaller FS_MAGIC_SIZE in main.c. -- Steven Shiau Tue, 22 Apr 2008 14:52:00 +0800 partclone (0.0.6-3) unstable; urgency=low # Bug fixed: version was not changed. -- Steven Shiau Thu, 21 Feb 2008 13:40:00 +0800 partclone (0.0.6-2) unstable; urgency=low # Bug fixed: clone.fat was not complied. -- Steven Shiau Wed, 20 Feb 2008 22:47:00 +0800 partclone (0.0.6-1) unstable; urgency=low # clone.fat was added by Thomas Tsai. -- Steven Shiau Wed, 20 Feb 2008 22:41:00 +0800 partclone (0.0.5-16) unstable; urgency=low # Typos fixed. # Bug fixed: partition to partition clone size checking failed. -- Steven Shiau Sat, 16 Feb 2008 10:02:00 +0800 partclone (0.0.5-15) unstable; urgency=low # partclone.nchc.org.tw was put without http:// in usage. -- Steven Shiau Mon, 04 Feb 2008 13:47:00 +0800 partclone (0.0.5-14) unstable; urgency=low # Some minor bugs fixed by Thomas Tsai. # http://partclone.nchc.org.tw was added in usage. -- Steven Shiau Mon, 04 Feb 2008 13:45:00 +0800 partclone (0.0.5-13) unstable; urgency=low * Bugs fixed and feature added by Thomas Tsai: # reduce seek time # fix number of Ave.Rate # check every filesystem's image_head data... # add new option to disable device and free space checking -- Steven Shiau Tue, 30 Jan 2008 23:07:00 +0800 partclone (0.0.5-12) unstable; urgency=low * Bug fixed by Thomas Tsai: Partition size checking failed in some cases. -- Steven Shiau Tue, 30 Jan 2008 21:08:00 +0800 partclone (0.0.5-11) unstable; urgency=low * Bug fixed by Thomas Tsai: Partition size checking failed -- Steven Shiau Tue, 29 Jan 2008 16:47:00 +0800 partclone (0.0.5-10) unstable; urgency=low * Functions to check memory size, check_free_space were added by Thomas Tsai. -- Steven Shiau Wed, 23 Jan 2008 22:57:00 +0800 partclone (0.0.5-9) unstable; urgency=low * Thomas Tsai added: New function rescue_sector. UNSTALBE feature, support device to device. Some other minor changes. -- Steven Shiau Sun, 20 Jan 2008 14:15:00 +0800 partclone (0.0.5-8) unstable; urgency=low * Some minor changes on ticket #18 from Thomas Tsai. -- Steven Shiau Fri, 11 Jan 2008 09:24:00 +0800 partclone (0.0.5-7) unstable; urgency=low * Some minor changes. -- Steven Shiau Wed, 9 Jan 2008 22:45:00 +0800 partclone (0.0.5-6) unstable; urgency=low * Thomas Tsai enhanced the status report. -- Steven Shiau Wed, 9 Jan 2008 09:15:00 +0800 partclone (0.0.5-5) unstable; urgency=low * Thomas Tsai closed ticket #18: Add a saving/restoring rate and estimated time to finish job in the status report. -- Steven Shiau Sun, 8 Jan 2008 15:12:00 +0800 partclone (0.0.5-4) unstable; urgency=low * Thomas Tsai closed these tickets: #12: Command without any option should show only short help messages. #13: Change "HFSPLUS" as "HFS+" or "HFS Plus". #15 (Sync after image is restored). #17: Show program name "partclone" and version number and url in the status report. -- Steven Shiau Sun, 7 Jan 2008 17:05:00 +0800 partclone (0.0.5-3) unstable; urgency=low * Static linking was disabled in debian/rules. -- Steven Shiau Sun, 6 Jan 2008 16:34:00 +0800 partclone (0.0.5-2) unstable; urgency=low * Description for deb package was updated. -- Steven Shiau Fri, 4 Jan 2008 21:40:00 +0800 partclone (0.0.5-1) unstable; urgency=low * [bugfix] reopen and close ticket #8 - fix debian packaging linking permission issue. -- Jazz Yao-Tsung Wang Fri, 4 Jan 2008 11:54:14 +0800 partclone (0.0.4-5) unstable; urgency=low * close ticket #8. Thomas added some alias programs when making install. -- Steven Shiau Fri, 4 Jan 2008 11:12:00 +0800 partclone (0.0.4-3ubuntu1) feisty; urgency=low * add support of static linking to configure.ac and src/Makefile.am * [BUGFIX #1] fixed static linking time error while enabling XFS file system support. * modified debian packaginf control and rules to fix some mistakes. -- Jazz Yao-Tsung Wang Wed, 2 Jan 2008 21:23:52 +0800 partclone (0.0.4-3) unstable; urgency=low * A Bug about restoring image from stdin was fixed by Jazz Wang. * zh_TW.po was updated. -- Steven Shiau Sun, 1 Jan 2008 20:20:00 +0800 partclone (0.0.4-2) unstable; urgency=low * Updated config by Jazz Wang so that static linking now it's better. Not finished. * Help messages updated. -- Steven Shiau Sun, 1 Jan 2008 11:20:00 +0800 partclone (0.0.4-1) unstable; urgency=low * Initial release. * modify rules -- Yu-Chin Tsai Thu, 13 Dec 2007 10:48:03 +0800 partclone-0.2.86/README.Packages/debian.jessie/compat000066400000000000000000000000021262102574200221520ustar00rootroot000000000000009 partclone-0.2.86/README.Packages/debian.jessie/control000066400000000000000000000024641262102574200223650ustar00rootroot00000000000000Source: partclone Section: admin Priority: extra Maintainer: Yu-Chin Tsai Build-Depends: debhelper (>= 9), dpkg-dev (>= 1.16.1~), dh-autoreconf, autotools-dev, pkg-config, xsltproc, docbook-xsl, docbook-xml, libncursesw5-dev, libtinfo-dev, e2fslibs-dev (>= 1.41.3), libbsd-dev, ntfs-3g-dev|libntfs-dev, xfslibs-dev, libreiserfs0.3-dev, libreiser4-dev, libufs2 (>= 7.2), libvmfs (>= 0.2.5), libjfs-dev, libblkid-dev, uuid-dev, nilfs-tools Standards-Version: 3.9.3 Package: partclone Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} Description: Utility to clone and restore a partition. This project like the well-known backup utility "Partition Image" a.k.a partimage. . Partclone provides utilities to back up used blocks and design for higher compatibility of the file system using supported library like e2fslibs. . check the project website for more details http://partclone.org Package: partclone-dbg Section: debug Priority: extra Architecture: any Depends: ${misc:Depends}, partclone (= ${binary:Version}) Description: Utility to clone and restore a partition for debug. This project like the well-known backup utility "Partition Image" a.k.a partimage. . This package contains the debugging symbols. . check the project website for more details http://partclone.org partclone-0.2.86/README.Packages/debian.jessie/copyright000066400000000000000000000067701262102574200227210ustar00rootroot00000000000000Format: http://dep.debian.net/deps/dep5 Upstream-Name: partclone Upstream-Contact: Yu-Chin Tsai Source: https://github.com/Thomas-Tsai/partclone Files: * Copyright: 2006-2012 Thomas Tsai 2007-2012 Steven Shiau 2007-2008 Jazz Wang License: GPL-2+ see below for the text of this license. Files: debian/* Copyright: 2012 Thomas Tsai 2011 Georges Khaznadar License: GPL-2+ see below for the text of this license. Files: src/ufs/libufs.h Copyright: 2002 Juli Mallett License: FreeBSD-like see below for the text of this license. Files: src/ufs/sys/* Copyright: 1987, 1988, 1993 The Regents of the University of California. License: FreeBSD-like see below for the text of this license. Files: src/ufs/ffs/* Copyright: 1982, 1986, 1993 The Regents of the University of California. License: FreeBSD-like see below for the text of this license. Files: src/ufs/ufs/fs.h Copyright: 1982, 1986, 1993 The Regents of the University of California. License: FreeBSD-like see below for the text of this license. Files: src/ufs/ufs/dinode.h Copyright: 2002 Networks Associates Technology, Inc. License: FreeBSD-like see below for the text of this license. License: FreeBSD-like Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 4. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. . THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. License: GPL-2+ This package is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. . This package is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. . You should have received a copy of the GNU General Public License along with this program. If not, see . On Debian systems, the complete text of the GNU General Public License version 2 can be found in "/usr/share/common-licenses/GPL-2". partclone-0.2.86/README.Packages/debian.jessie/dirs000066400000000000000000000000111262102574200216300ustar00rootroot00000000000000usr/sbin partclone-0.2.86/README.Packages/debian.jessie/docs000066400000000000000000000000171262102574200216250ustar00rootroot00000000000000NEWS README.md partclone-0.2.86/README.Packages/debian.jessie/rules000077500000000000000000000026201262102574200220340ustar00rootroot00000000000000#!/usr/bin/make -f # -*- makefile -*- # Sample debian/rules that uses debhelper. # This file was originally written by Joey Hess and Craig Small. # As a special exception, when this file is copied by dh-make into a # dh-make output file, you may use that output file without restriction. # This special exception was added by Craig Small in version 0.37 of dh-make. # Uncomment this to turn on verbose mode. export DH_VERBOSE=1 DPKG_EXPORT_BUILDFLAGS = 1 include /usr/share/dpkg/buildflags.mk %: dh $@ --with autoreconf --with autotools-dev override_dh_auto_configure: # Add here commands to configure the package. #cp /usr/share/misc/config.sub . #cp /usr/share/misc/config.guess . #autoreconf #./configure --prefix=/usr --mandir=\$${prefix}/share/man --infodir=\$${prefix}/share/info LDFLAGS="-Wl,-z,defs" --enable-ncursesw --enable-extfs --enable-static # dh_auto_configure -- --enable-ncursesw --enable-extfs --enable-static # for normal linux dh_auto_configure -- --enable-ncursesw --enable-all --enable-static # for clonezilla dist override_dh_auto_install: $(MAKE) DESTDIR=$$(pwd)/debian/partclone prefix=/usr install override_dh_auto_clean: dh_auto_clean rm -f get_lib_version rm -f config.sub configure Makefile.in aclocal.m4 config.guess rm -f src/Makefile.in docs/Makefile.in override_dh_clean: dh_clean -X fail-mbr/fail-mbr.bin.orig override_dh_strip: dh_strip --dbg-package=partclone-dbg partclone-0.2.86/README.Packages/debian.jessie/source/000077500000000000000000000000001262102574200222545ustar00rootroot00000000000000partclone-0.2.86/README.Packages/debian.jessie/source/format000066400000000000000000000000141262102574200234620ustar00rootroot000000000000003.0 (quilt) partclone-0.2.86/README.Packages/debian.sid/000077500000000000000000000000001262102574200202515ustar00rootroot00000000000000partclone-0.2.86/README.Packages/debian.sid/changelog000066400000000000000000000626541262102574200221400ustar00rootroot00000000000000partclone (0.2.52-1) unstable; urgency=low * update debian control * update TODO * update ncurses interface. -- Yu-Chin Tsai Fri, 21 Sep 2012 09:59:32 +0800 partclone (0.2.51) unstable; urgency=low * update makefile * update supported list * update process for elapsed time over 24hr * update version to 0.2.51 * update some docs -- Thomas Tsai Thu, 20 Sep 2012 17:07:41 +0800 partclone (0.2.50) unstable; urgency=low * release 0.2.49 * update control * update control * add partclone.btrfs.8 * add more detail message in image head output * add exfat * update exfat and add exfat man docs * add test for exfat * update test and size information * version 0.2.50 -- Thomas Tsai Tue, 10 Jul 2012 16:39:19 +0800 partclone (0.2.49) unstable; urgency=low * release 0.2.48 * update TODO * minor update readme * update docs * update docs * update manpage * fix quiet mode issue. The issue make partclone can't stop/finish even action is done. bug report from pille -- Thomas Tsai Tue, 10 Jul 2012 16:35:27 +0800 partclone (0.2.48) unstable; urgency=low [ Thomas Tsai ] * update debian control for vmfs-tools [ thomas ] * ignore unallocated block for vmfs [ Thomas Tsai ] * update bitmap progress * A partclone bug found when it backs up WindowsServer2008R2 (64bit) * update vmfs for some unallocated block -- Thomas Tsai Tue, 01 May 2012 11:32:47 +0800 partclone (0.2.47) unstable; urgency=low * try to fix ID: 3509757 from clonezilla track system * change row to raw, noticed from Vincent van Adrighem * update fresh, add sleep in progress thread to reduce cpu usage, contributed and bug information from http://sourceforge.net/tracker/?func=detail&aid=3509757&group_id=115473&atid=671650 * update fresh done * 0.2.47 -- Thomas Tsai Wed, 18 Apr 2012 13:41:31 +0800 partclone (0.2.46) unstable; urgency=low * accept part of patch from Matthew Booth's review * update partclone.vmfs for version 5 * update manpages * update document, some example error. * update vmfsclone to backup vmfs5 well * accept patch from Rommer to update memory usage * and release 0.2.46 -- Thomas Tsai Mon, 02 Apr 2012 09:14:23 +0800 partclone (0.2.45) unstable; urgency=low * print vmfs version from fstype * add compatibility of vmfs3 and vmfs5 -- Thomas Tsai Wed, 18 Jan 2012 10:39:22 +0800 partclone (0.2.44) unstable; urgency=low * update pui for mode dev-to-dev -- Thomas Tsai Tue, 17 Jan 2012 15:11:30 +0800 partclone (0.2.43) unstable; urgency=low * 0.2.43 -- Thomas Tsai Tue, 27 Dec 2011 16:25:57 +0800 partclone (0.2.42) unstable; urgency=low * add option B to disable block detail; old progress style. * add finish progress to dd * 0.2.42 -- Thomas Tsai Tue, 27 Dec 2011 15:58:55 +0800 partclone (0.2.41) unstable; urgency=low * add block status * update progress bar * add thread to display progress, draft * add thread to dd, restore and chkimg * 0.2.41 -- Thomas Tsai Tue, 27 Dec 2011 00:53:41 +0800 partclone (0.2.40) unstable; urgency=low * update progress seeking at 100% -- Thomas Tsai Fri, 23 Dec 2011 10:25:43 +0800 partclone (0.2.39) unstable; urgency=low * 0.2.39 * updaet ntfsfixboot to version 1.0 -- Thomas Tsai Mon, 12 Dec 2011 14:49:22 +0800 partclone (0.2.38) unstable; urgency=low * update for makefile for ncursesw * update for progress * 0.2.38 -- Thomas Tsai Mon, 12 Dec 2011 14:27:23 +0800 partclone (0.2.37) unstable; urgency=low * add -I/usr/include/ncursesw/ * release 0.2.37 -- Thomas Tsai Wed, 23 Nov 2011 16:32:09 +0800 partclone (0.2.36) unstable; urgency=low * update ncurses size * 0.2.36 -- Thomas Tsai Wed, 23 Nov 2011 16:31:06 +0800 partclone (0.2.35) unstable; urgency=low * move debian folder to README.Packages as sample * update control for debian-sid * save last changelog ($version) * update version script * add debian * re remove debian * update TODO * add debian * remove debian * add debian * move partclone.spec to README.Packages/partclone.spec * update * align version and tag * update toolbox -- Thomas Tsai Wed, 02 Nov 2011 01:07:24 +0800 partclone (0.2.34) unstable; urgency=low * update autoconf and automake for squeeze -- Thomas Tsai Tue, 01 Nov 2011 11:32:42 +0800 partclone (0.2.33) unstable; urgency=low * update makefile for ncurses static linking * update memory usage * update ncurses progress bar -- Thomas Tsai Thu, 27 Oct 2011 22:05:17 +0800 partclone (0.2.32) unstable; urgency=low * accept patch file from Rommer. * Attached patch for partclone 0.2.31 reduces memory usage by 4-8 times. by Rommer. -- Thomas Tsai Wed, 12 Oct 2011 21:27:43 +0800 partclone (0.2.31) unstable; urgency=low * update for vmfs5 -- Thomas Tsai Wed, 12 Oct 2011 21:27:43 +0800 partclone (0.2.30) unstable; urgency=low * patch for new vmfs-tools -- Thomas Tsai Tue, 11 Oct 2011 21:21:24 +0800 partclone (0.2.29) unstable; urgency=low * fix bugs * release 0.2.29 -- Thomas Tsai Mon, 12 Sep 2011 21:21:24 +0800 partclone (0.2.28) unstable; urgency=low * update e2fslibs for squeeze * fix bug for ntfsclone with ncurses on unstable -- Thomas Tsai Thu, 08 Sep 2011 22:58:27 +0800 partclone (0.2.27) unstable; urgency=low * accept patch from Georges about configure, fixIntTypes and typos in manpages * try to fix issue for bitmap, suggestion from Paul. -- Thomas Tsai Tue, 30 Aug 2011 11:45:06 +0800 partclone (0.2.26) unstable; urgency=low * update test script -- Thomas Tsai Mon, 15 Aug 2011 10:45:06 +0800 partclone (0.2.25) unstable; urgency=low * update for e2fslibs 1.42~WIP-2011-07-02 * compact ntfs and ntfs-3g -- Thomas Tsai Mon, 15 Aug 2011 10:45:06 +0800 partclone (0.2.24) natty; urgency=low * accept patch from Ian Abbott. * '--domain' (-D) and -offset_domain=X to generate domain file for ddrescue. -- Thomas Tsai Tue, 24 May 2011 10:45:06 +0800 partclone (0.2.23) maverick; urgency=low * update manpages -- Thomas Tsai Fri, 22 Apr 2011 11:02:59 +0800 partclone (0.2.22) maverick; urgency=low * typo error for progress -- Thomas Tsai Mon, 28 Mar 2011 15:19:16 +0800 partclone (0.2.21) maverick; urgency=low * fix bug for partclone.dd and partclone.restore for stdin dd data. -- Thomas Tsai Tue, 22 Mar 2011 14:21:11 +0800 partclone (0.2.20) maverick; urgency=low * fix dd issue. set default size as target size for stdin data. -- Thomas Tsai Mon, 14 Mar 2011 10:12:19 +0800 partclone (0.2.19) unstable; urgency=low * update makefile for btrf -- Thomas Tsai Wed, 09 Mar 2011 14:06:05 +0800 partclone (0.2.18) unstable; urgency=low * add option max_block_cache to get better performance escpcially small block size(fat) * update typo error -- Thomas Tsai Tue, 25 Jan 2011 16:06:05 +0800 partclone (0.2.17) unstable; urgency=low * update for ext4 metadata mismatch issue * update makefile and configure -- Thomas Tsai Tue, 25 Jan 2011 16:06:05 +0800 partclone (0.2.16) unstable; urgency=low * add option --quiet to disable progress bar * add option --restore_row_file to create special file for mounting with loop option -- Thomas Tsai Wed, 06 Oct 2010 16:06:05 +0800 partclone (0.2.15) unstable; urgency=low * Bug fixed: btrfs clone fail, lost some metadata message * Add po: add fr_FR po file from Cédric, very thanks. -- Thomas Tsai Wed, 01 Sep 2010 10:25:48 +0800 partclone (0.2.14) unstable; urgency=low * add btrfs support -- Thomas Tsai Sun, 22 Aug 2010 15:14:20 +0800 partclone (0.2.13) unstable; urgency=low * add link partclone.VMFS_volume_member * fix bug: jfsclone segfault * add debian/control pkg-config -- Thomas Tsai Wed, 28 Jul 2010 17:14:20 +0800 partclone (0.2.12) unstable; urgency=low * New Feature: The jfs filesystem is supported. -- Thomas Tsai Wed, 30 Jun 2010 11:58:41 +0800 partclone (0.2.11) unstable; urgency=low * Bug fixed: xfsclone type error for amd64 * Update control file: add libvmfs -- Thomas Tsai Wed, 19 May 2010 12:22:07 +0800 partclone (0.2.10) unstable; urgency=low * Bug fixed: chkimg.c not work * Bug fixed: new xfsclone -- Thomas Tsai Wed, 19 May 2010 12:22:07 +0800 partclone (0.2.9) unstable; urgency=low * Bug fixed: error for backup partition larger than 8.7T * Bug fixed: better memory usage for restore -- Thomas Tsai Thu, 29 Apr 2010 15:22:07 +0800 partclone (0.2.8) unstable; urgency=low * Bug fixed: update progress bar faster -- Thomas Tsai Mon, 29 Mar 2010 16:22:38 +0800 partclone (0.2.7-1) unstable; urgency=low * fix progress bug about: alwayn new line for 640x480 resolution * update version -- Thomas Tsai Tue, 16 Mar 2010 15:13:04 +0800 partclone (0.2.6-1) unstable; urgency=low * update version -- Thomas Tsai Mon, 15 Mar 2010 11:29:18 +0800 partclone (0.2.5-1) unstable; urgency=low * A bug about 0 rate for bitmap calculation. * update partclone to show more readable size for partition and rate/min. -- Thomas Tsai Fri, 12 Mar 2010 09:15:31 +0800 partclone (0.2.4-1) unstable; urgency=low * autogen git number * fix progress inf bug -- Thomas Tsai Wed, 10 Mar 2010 16:30:55 +0800 partclone (0.2.3-1) unstable; urgency=low * add partclone.fstype to test filesystem type (vmfs only) * update svn versionto git version -- Thomas Tsai Tue, 02 Mar 2010 13:50:26 +0800 partclone (0.2.0-2) unstable; urgency=low * VMFS supported in this release. -- Steven Shiau Sun, 14 Feb 2010 15:00:00 +0800 partclone (0.2.0-1) unstable; urgency=low [ Yu-Chin Tsai ] * A test release. -- Thomas Tsai Wed, 06 Jan 2010 16:07:05 +0800 partclone (0.1.9-5) unstable; urgency=low [ Yu-Chin Tsai ] * A bug about hfsplus error for 2 or more extents was fixed. -- Steven Shiau Wed, 25 Nov 2009 16:54:00 +0800 partclone (0.1.9-4) unstable; urgency=low * update configure.ac, set ufs as default enabled file system. * update progress bar to show the "100%" in the end. -- Yu-Chin Tsai Mon, 16 Nov 2009 14:46:04 +0800 partclone (0.1.9-3) unstable; urgency=low [ Yu-Chin Tsai ] * An option to ignore CRC checking was added. -- Steven Shiau Tue, 03 Nov 2009 17:16:00 +0800 partclone (0.1.9-2) unstable; urgency=low [ Yu-Chin Tsai ] * Bug fixed: update log message and open fail message for ufsclone. Thanks to dswartz for testing ufs backup and report. -- Steven Shiau Fri, 09 Oct 2009 11:14:00 +0800 partclone (0.1.9-1) unstable; urgency=low [ Yu-Chin Tsai ] * Bug fixed: XFS clone failure was fixed. * UFS was added. -- Yu-Chin Tsai Thu, 17 Sep 2009 14:07:33 +0800 partclone (0.1.1-16) unstable; urgency=low [Thomas Tsai] * Bug fixed: FAT clone failure was fixed. -- Steven Shiau Sun, 09 Aug 2009 08:49:00 +0800 partclone (0.1.1-15) unstable; urgency=low [Thomas Tsai] * Bug fixed: Wrong path for exec files. -- Steven Shiau Wed, 24 Jun 2009 16:48:00 +0800 partclone (0.1.1-14) unstable; urgency=low [Thomas Tsai] * Bug fixed: version number from SVN was not shown correctly. -- Steven Shiau Wed, 24 Jun 2009 14:36:00 +0800 partclone (0.1.1-13) unstable; urgency=low [Thomas Tsai] * Prompt messages were updated. -- Steven Shiau Fri, 18 Jun 2009 13:30:00 +0800 partclone (0.1.1-12) unstable; urgency=low [Thomas Tsai] * An option was added: --logfile or -L to specify file for log message. * A new program partclone.chkimg was added to help checking img by CRC. -- Steven Shiau Wed, 17 Jun 2009 10:34:00 +0800 partclone (0.1.1-11) unstable; urgency=low [Thomas Tsai] * update clear_buf * The patch from Kristian Erik Hermansen. fix progress.c:152- SECURITY: fprintf call should have "%s" as argument 1 -- Steven Shiau Sat, 13 Jun 2009 14:39:00 +0800 partclone (0.1.1-10) unstable; urgency=low [Thomas Tsai] * Bug fixed: pointer problem was fixed. * Bug fixed: buffer overflow problem was fixed. Thanks to Kristian Erik Hermansen and Piavlo. * Bug fixed: a bug about hfs+ was fixed. -- Steven Shiau Wed, 10 Jun 2009 10:39:00 +0800 partclone (0.1.1-9) unstable; urgency=low [Steven Shiau] * Some output messages were polished again. -- Steven Shiau Tue, 02 Jun 2009 18:09:00 +0800 partclone (0.1.1-8) unstable; urgency=low [Thomas Tsai] * Some output messages were polished. -- Steven Shiau Tue, 02 Jun 2009 16:51:00 +0800 partclone (0.1.1-7) unstable; urgency=low [Thomas Tsai] * Bug fixed: Progress update with nogui, "Calculating bitmap..." was added without option -d. -- Steven Shiau Mon, 01 Jun 2009 22:36:00 +0800 partclone (0.1.1-6) unstable; urgency=low [Thomas Tsai] * bug of CRC in 64 bit image problem was fixed. A better method will be imlemented in the nexe version of image format. -- Steven Shiau Sat, 30 May 2009 12:10:00 +0800 partclone (0.1.1-5) unstable; urgency=low [Thomas Tsai] * bug of time calculating was fixed. -- Steven Shiau Wed, 27 May 2009 22:13:00 +0800 partclone (0.1.1-4) unstable; urgency=low [Thomas Tsai] * Update default RES from 10000 to 1000. -- Steven Shiau Wed, 27 May 2009 12:59:00 +0800 partclone (0.1.1-3) unstable; urgency=low [Thomas Tsai] * Bug fixed: block device should not have to use "--overwrite". -- Steven Shiau Wed, 27 May 2009 11:23:00 +0800 partclone (0.1.1-2) unstable; urgency=low [Thomas Tsai] * partclone.ntfsreloc is linked to partclone.ntfsfixboot. -- Steven Shiau Fri, 22 May 2009 13:52:00 +0800 partclone (0.1.1-1) unstable; urgency=low [Thomas Tsai] * Minor updates for output messages. * New Feature: add argument to set fresh of progress bar * New Feature: restore to new file(non-block device) * A bug about crc check in 64bit image * Update partclone.ntfsreloc to ntfsfixboot.c from http://cc.jct.ac.il/~shaneh/ntfsfixboot.c -- root Fri, 22 May 2009 05:52:00 +0800 partclone (0.1.0-10) unstable; urgency=low [ Thomas Tsai ] * Bug fixed: clonezilla-Bugs-2784676. Thanks to njorl _at_ users sourceforge net. -- Steven Shiau Fri, 01 May 2009 10:55:00 +0800 partclone (0.1.0-9) unstable; urgency=low [ Steven Shiau ] * Minor updates for output messages. -- Steven Shiau Sun, 26 Apr 2009 13:54:00 +0800 partclone (0.1.0-8) unstable; urgency=low [ Steven Shiau ] * Minor updates for output messages. [ Thomas Tsai ] * EXECNAME was added for partclone.restore. -- Steven Shiau Fri, 24 Apr 2009 14:07:00 +0800 partclone (0.1.0-7) unstable; urgency=low [ Thomas Tsai ] * partclone.ext4dev is linkded now. -- Steven Shiau Thu, 23 Apr 2009 19:01:00 +0800 partclone (0.1.0-6) unstable; urgency=low [ Thomas Tsai ] * A bug about partclone.restore used to restore known file systems was fixed. -- Steven Shiau Thu, 18 Apr 2009 09:59:00 +0800 partclone (0.1.0-5) unstable; urgency=low [ Thomas Tsai ] * A bug about checking partition size was fixed. -- Steven Shiau Thu, 16 Apr 2009 15:03:00 +0800 partclone (0.1.0-4) unstable; urgency=low [ Thomas Tsai ] * Local device to device copy mode option "-b, --dd-mode" was changed to be "-b, --dev-to-dev" * A bug about partclone.dd wrongly get the partition size was fixed. -- Steven Shiau Thu, 16 Apr 2009 12:16:00 +0800 partclone (0.1.0-3) unstable; urgency=low [ Thomas Tsai ] * Bug fixed: partclone.ntfs statistics data was wrong when doing partition to partition clone. -- Steven Shiau Tue, 15 Apr 2009 10:52:00 +0800 partclone (0.1.0-2) unstable; urgency=low [ Steven Shiau ] * --enable-static is on again. -- Steven Shiau Tue, 10 Apr 2009 11:47:00 +0800 partclone (0.1.0-1) unstable; urgency=low [ Thomas Tsai ] * partclone.ext4, partclone.dd, partclone.restore were added. -- Steven Shiau Tue, 07 Apr 2009 15:01:00 +0800 partclone (0.0.9-4) unstable; urgency=low [ Thomas Tsai ] * A bug about FAT12 was fixed. -- Steven Shiau Tue, 30 Dec 2008 13:41:00 +0800 partclone (0.0.9-3) unstable; urgency=low [ Steven Shiau ] * New upstream ntfsreloc.c 0.8. -- Steven Shiau Thu, 25 Dec 2008 15:32:00 +0800 partclone (0.0.9-2) unstable; urgency=low [ Thomas Tsai ] * Update dirty message for ntfsclone-ng. * Check filesystem before cloning partition. Partclone will make sure that. * Add check hfs_plus filesystem before cloning volume. * Update fatclone.c fatclone.h clearly. update dirty message for extfs. -- Steven Shiau Mon, 22 Dec 2008 09:46:00 +0800 partclone (0.0.9-1) unstable; urgency=low # New features: partclone.ntfsreloc and partclone.ntfs were added. -- Steven Shiau Thu, 30 Oct 2008 10:51:00 +0800 partclone (0.0.8-8) unstable; urgency=low # Bug fixed: Failing to restore fat32 image was fixed by Thomas Tsai. -- Steven Shiau Wed, 30 Jul 2008 09:18:00 +0800 partclone (0.0.8-7) unstable; urgency=low # partclone.hfsplus link was added by Thomas Tsai. -- Steven Shiau Thu, 24 Jul 2008 11:53:00 +0800 partclone (0.0.8-6) unstable; urgency=low # Bug fixed: partclone.fat12 link was not done. -- Steven Shiau Fri, 11 Jul 2008 16:11:00 +0800 partclone (0.0.8-5) unstable; urgency=low # fat12 was added by Thomas Tsai. -- Steven Shiau Fri, 11 Jul 2008 15:03:00 +0800 partclone (0.0.8-4) unstable; urgency=low # Enable static linking. -- Steven Shiau Sat, 28 Jun 2008 10:22:00 +0800 partclone (0.0.8-3) unstable; urgency=low # Some minor updates about messages by Thomas Tsai. -- Steven Shiau Sun, 15 Jun 2008 22:48:00 +0800 partclone (0.0.8-2) unstable; urgency=low # configure.ac updated by Thomas Tsai. # partclone website is www.partclone.org now. -- Steven Shiau Mon, 26 May 2008 14:19:00 +0800 partclone (0.0.8-1) unstable; urgency=low # clone.$FS was renamed as partclone.$FS by Thomas Tsai. -- Steven Shiau Sun, 25 May 2008 09:19:00 +0800 partclone (0.0.7-4) unstable; urgency=low # Some bugs about ncursesw were fixed by Thomas Tsai. -- Steven Shiau Fri, 16 May 2008 16:18:00 +0800 partclone (0.0.7-3) unstable; urgency=low # Some bugs about ncursesw were fixed by Thomas Tsai. -- Steven Shiau Thu, 06 May 2008 23:00:00 +0800 partclone (0.0.7-2) unstable; urgency=low # Use --enable-ncursesw by default. -- Steven Shiau Thu, 01 May 2008 11:13:00 +0800 partclone (0.0.7-1) unstable; urgency=low # New functions: TUI mode for output done by Thomas Tsai. -- Steven Shiau Thu, 01 May 2008 11:08:00 +0800 partclone (0.0.6-4) unstable; urgency=low # Some new function for #14 "TUI of status reports" from Thomas Tsai. # Smaller FS_MAGIC_SIZE in main.c. -- Steven Shiau Tue, 22 Apr 2008 14:52:00 +0800 partclone (0.0.6-3) unstable; urgency=low # Bug fixed: version was not changed. -- Steven Shiau Thu, 21 Feb 2008 13:40:00 +0800 partclone (0.0.6-2) unstable; urgency=low # Bug fixed: clone.fat was not complied. -- Steven Shiau Wed, 20 Feb 2008 22:47:00 +0800 partclone (0.0.6-1) unstable; urgency=low # clone.fat was added by Thomas Tsai. -- Steven Shiau Wed, 20 Feb 2008 22:41:00 +0800 partclone (0.0.5-16) unstable; urgency=low # Typos fixed. # Bug fixed: partition to partition clone size checking failed. -- Steven Shiau Sat, 16 Feb 2008 10:02:00 +0800 partclone (0.0.5-15) unstable; urgency=low # partclone.nchc.org.tw was put without http:// in usage. -- Steven Shiau Mon, 04 Feb 2008 13:47:00 +0800 partclone (0.0.5-14) unstable; urgency=low # Some minor bugs fixed by Thomas Tsai. # http://partclone.nchc.org.tw was added in usage. -- Steven Shiau Mon, 04 Feb 2008 13:45:00 +0800 partclone (0.0.5-13) unstable; urgency=low * Bugs fixed and feature added by Thomas Tsai: # reduce seek time # fix number of Ave.Rate # check every filesystem's image_head data... # add new option to disable device and free space checking -- Steven Shiau Tue, 30 Jan 2008 23:07:00 +0800 partclone (0.0.5-12) unstable; urgency=low * Bug fixed by Thomas Tsai: Partition size checking failed in some cases. -- Steven Shiau Tue, 30 Jan 2008 21:08:00 +0800 partclone (0.0.5-11) unstable; urgency=low * Bug fixed by Thomas Tsai: Partition size checking failed -- Steven Shiau Tue, 29 Jan 2008 16:47:00 +0800 partclone (0.0.5-10) unstable; urgency=low * Functions to check memory size, check_free_space were added by Thomas Tsai. -- Steven Shiau Wed, 23 Jan 2008 22:57:00 +0800 partclone (0.0.5-9) unstable; urgency=low * Thomas Tsai added: New function rescue_sector. UNSTALBE feature, support device to device. Some other minor changes. -- Steven Shiau Sun, 20 Jan 2008 14:15:00 +0800 partclone (0.0.5-8) unstable; urgency=low * Some minor changes on ticket #18 from Thomas Tsai. -- Steven Shiau Fri, 11 Jan 2008 09:24:00 +0800 partclone (0.0.5-7) unstable; urgency=low * Some minor changes. -- Steven Shiau Wed, 9 Jan 2008 22:45:00 +0800 partclone (0.0.5-6) unstable; urgency=low * Thomas Tsai enhanced the status report. -- Steven Shiau Wed, 9 Jan 2008 09:15:00 +0800 partclone (0.0.5-5) unstable; urgency=low * Thomas Tsai closed ticket #18: Add a saving/restoring rate and estimated time to finish job in the status report. -- Steven Shiau Sun, 8 Jan 2008 15:12:00 +0800 partclone (0.0.5-4) unstable; urgency=low * Thomas Tsai closed these tickets: #12: Command without any option should show only short help messages. #13: Change "HFSPLUS" as "HFS+" or "HFS Plus". #15 (Sync after image is restored). #17: Show program name "partclone" and version number and url in the status report. -- Steven Shiau Sun, 7 Jan 2008 17:05:00 +0800 partclone (0.0.5-3) unstable; urgency=low * Static linking was disabled in debian/rules. -- Steven Shiau Sun, 6 Jan 2008 16:34:00 +0800 partclone (0.0.5-2) unstable; urgency=low * Description for deb package was updated. -- Steven Shiau Fri, 4 Jan 2008 21:40:00 +0800 partclone (0.0.5-1) unstable; urgency=low * [bugfix] reopen and close ticket #8 - fix debian packaging linking permission issue. -- Jazz Yao-Tsung Wang Fri, 4 Jan 2008 11:54:14 +0800 partclone (0.0.4-5) unstable; urgency=low * close ticket #8. Thomas added some alias programs when making install. -- Steven Shiau Fri, 4 Jan 2008 11:12:00 +0800 partclone (0.0.4-3ubuntu1) feisty; urgency=low * add support of static linking to configure.ac and src/Makefile.am * [BUGFIX #1] fixed static linking time error while enabling XFS file system support. * modified debian packaginf control and rules to fix some mistakes. -- Jazz Yao-Tsung Wang Wed, 2 Jan 2008 21:23:52 +0800 partclone (0.0.4-3) unstable; urgency=low * A Bug about restoring image from stdin was fixed by Jazz Wang. * zh_TW.po was updated. -- Steven Shiau Sun, 1 Jan 2008 20:20:00 +0800 partclone (0.0.4-2) unstable; urgency=low * Updated config by Jazz Wang so that static linking now it's better. Not finished. * Help messages updated. -- Steven Shiau Sun, 1 Jan 2008 11:20:00 +0800 partclone (0.0.4-1) unstable; urgency=low * Initial release. * modify rules -- Yu-Chin Tsai Thu, 13 Dec 2007 10:48:03 +0800 partclone-0.2.86/README.Packages/debian.sid/compat000066400000000000000000000000021262102574200214470ustar00rootroot000000000000009 partclone-0.2.86/README.Packages/debian.sid/control000066400000000000000000000024641262102574200216620ustar00rootroot00000000000000Source: partclone Section: admin Priority: extra Maintainer: Yu-Chin Tsai Build-Depends: debhelper (>= 9), dpkg-dev (>= 1.16.1~), dh-autoreconf, autotools-dev, pkg-config, xsltproc, docbook-xsl, docbook-xml, libncursesw5-dev, libtinfo-dev, e2fslibs-dev (>= 1.41.3), libbsd-dev, ntfs-3g-dev|libntfs-dev, xfslibs-dev, libreiserfs0.3-dev, libreiser4-dev, libufs2 (>= 7.2), libvmfs (>= 0.2.5), libjfs-dev, libblkid-dev, uuid-dev, nilfs-tools Standards-Version: 3.9.3 Package: partclone Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} Description: Utility to clone and restore a partition. This project like the well-known backup utility "Partition Image" a.k.a partimage. . Partclone provides utilities to back up used blocks and design for higher compatibility of the file system using supported library like e2fslibs. . check the project website for more details http://partclone.org Package: partclone-dbg Section: debug Priority: extra Architecture: any Depends: ${misc:Depends}, partclone (= ${binary:Version}) Description: Utility to clone and restore a partition for debug. This project like the well-known backup utility "Partition Image" a.k.a partimage. . This package contains the debugging symbols. . check the project website for more details http://partclone.org partclone-0.2.86/README.Packages/debian.sid/copyright000066400000000000000000000067701262102574200222160ustar00rootroot00000000000000Format: http://dep.debian.net/deps/dep5 Upstream-Name: partclone Upstream-Contact: Yu-Chin Tsai Source: https://github.com/Thomas-Tsai/partclone Files: * Copyright: 2006-2012 Thomas Tsai 2007-2012 Steven Shiau 2007-2008 Jazz Wang License: GPL-2+ see below for the text of this license. Files: debian/* Copyright: 2012 Thomas Tsai 2011 Georges Khaznadar License: GPL-2+ see below for the text of this license. Files: src/ufs/libufs.h Copyright: 2002 Juli Mallett License: FreeBSD-like see below for the text of this license. Files: src/ufs/sys/* Copyright: 1987, 1988, 1993 The Regents of the University of California. License: FreeBSD-like see below for the text of this license. Files: src/ufs/ffs/* Copyright: 1982, 1986, 1993 The Regents of the University of California. License: FreeBSD-like see below for the text of this license. Files: src/ufs/ufs/fs.h Copyright: 1982, 1986, 1993 The Regents of the University of California. License: FreeBSD-like see below for the text of this license. Files: src/ufs/ufs/dinode.h Copyright: 2002 Networks Associates Technology, Inc. License: FreeBSD-like see below for the text of this license. License: FreeBSD-like Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 4. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. . THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. License: GPL-2+ This package is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. . This package is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. . You should have received a copy of the GNU General Public License along with this program. If not, see . On Debian systems, the complete text of the GNU General Public License version 2 can be found in "/usr/share/common-licenses/GPL-2". partclone-0.2.86/README.Packages/debian.sid/dirs000066400000000000000000000000111262102574200211250ustar00rootroot00000000000000usr/sbin partclone-0.2.86/README.Packages/debian.sid/docs000066400000000000000000000000171262102574200211220ustar00rootroot00000000000000NEWS README.md partclone-0.2.86/README.Packages/debian.sid/rules000077500000000000000000000026201262102574200213310ustar00rootroot00000000000000#!/usr/bin/make -f # -*- makefile -*- # Sample debian/rules that uses debhelper. # This file was originally written by Joey Hess and Craig Small. # As a special exception, when this file is copied by dh-make into a # dh-make output file, you may use that output file without restriction. # This special exception was added by Craig Small in version 0.37 of dh-make. # Uncomment this to turn on verbose mode. export DH_VERBOSE=1 DPKG_EXPORT_BUILDFLAGS = 1 include /usr/share/dpkg/buildflags.mk %: dh $@ --with autoreconf --with autotools-dev override_dh_auto_configure: # Add here commands to configure the package. #cp /usr/share/misc/config.sub . #cp /usr/share/misc/config.guess . #autoreconf #./configure --prefix=/usr --mandir=\$${prefix}/share/man --infodir=\$${prefix}/share/info LDFLAGS="-Wl,-z,defs" --enable-ncursesw --enable-extfs --enable-static # dh_auto_configure -- --enable-ncursesw --enable-extfs --enable-static # for normal linux dh_auto_configure -- --enable-ncursesw --enable-all --enable-static # for clonezilla dist override_dh_auto_install: $(MAKE) DESTDIR=$$(pwd)/debian/partclone prefix=/usr install override_dh_auto_clean: dh_auto_clean rm -f get_lib_version rm -f config.sub configure Makefile.in aclocal.m4 config.guess rm -f src/Makefile.in docs/Makefile.in override_dh_clean: dh_clean -X fail-mbr/fail-mbr.bin.orig override_dh_strip: dh_strip --dbg-package=partclone-dbg partclone-0.2.86/README.Packages/debian.sid/source/000077500000000000000000000000001262102574200215515ustar00rootroot00000000000000partclone-0.2.86/README.Packages/debian.sid/source/format000066400000000000000000000000141262102574200227570ustar00rootroot000000000000003.0 (quilt) partclone-0.2.86/README.Packages/debian.squeeze/000077500000000000000000000000001262102574200211535ustar00rootroot00000000000000partclone-0.2.86/README.Packages/debian.squeeze/compat000066400000000000000000000000021262102574200223510ustar00rootroot000000000000005 partclone-0.2.86/README.Packages/debian.squeeze/control000066400000000000000000000024251262102574200225610ustar00rootroot00000000000000Source: partclone Section: admin Priority: extra Maintainer: Yu-Chin Tsai , Jazz Yao-Tsung Wang Build-Depends: debhelper (>= 5), autotools-dev, e2fslibs-dev (>= 1.41.3), xfslibs-dev, libreiserfs0.3-dev, libreiser4-dev, libufs2 (>= 7.2), libbsd-dev, libncursesw5-dev, ntfs-3g-dev|libntfs-dev, libvmfs (>= 0.2.5), libjfs-dev, pkg-config, xsltproc, docbook-xsl, libblkid-dev, nilfs-tools Standards-Version: 3.7.2 Package: partclone Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} Description: The utility to clone and restore a partition. Partclone is a project like the well-known backup utility "Partition Image" a.k.a partimage. . Partclone provides utilities to back up used blocks and design for higher compatibility of the file system using supported library like e2fslibs. . check the project website for more details http://partclone.org Package: partclone-dbg Section: debug Priority: extra Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} Description: The utility to clone and restore a partition. Partclone is a project like the well-known backup utility "Partition Image" a.k.a partimage. . This package contains the debugging symbols. . check the project website for more details http://partclone.org partclone-0.2.86/README.Packages/debian.squeeze/copyright000066400000000000000000000024711262102574200231120ustar00rootroot00000000000000This package was debianized by Yu-Chin Tsai on Thu, 13 Dec 2007 09:51:06 +0800. It was downloaded from Upstream Author(s): Thomas Tsai Jazz Wang Copyright: Copyright (C) 2006, 2007 by Jazz Wang (jazz _at_ nchc org tw) Thomas Tsai (thomas _at_ nchc org tw) License: This package is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This package is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this package; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA On Debian systems, the complete text of the GNU General Public License can be found in `/usr/share/common-licenses/GPL'. The Debian packaging is (C) 2007, Yu-Chin Tsai and is licensed under the GPL, see above. partclone-0.2.86/README.Packages/debian.squeeze/dirs000066400000000000000000000000111262102574200220270ustar00rootroot00000000000000usr/sbin partclone-0.2.86/README.Packages/debian.squeeze/docs000066400000000000000000000000171262102574200220240ustar00rootroot00000000000000NEWS README.md partclone-0.2.86/README.Packages/debian.squeeze/rules000077500000000000000000000051571262102574200222430ustar00rootroot00000000000000#!/usr/bin/make -f # -*- makefile -*- # Sample debian/rules that uses debhelper. # This file was originally written by Joey Hess and Craig Small. # As a special exception, when this file is copied by dh-make into a # dh-make output file, you may use that output file without restriction. # This special exception was added by Craig Small in version 0.37 of dh-make. # Uncomment this to turn on verbose mode. #export DH_VERBOSE=1 # These are used for cross-compiling and for saving the configure script # from having to guess our platform (since we know it already) DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE) DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE) CFLAGS = -Wall -g ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS))) CFLAGS += -O0 else CFLAGS += -O2 endif config.status: configure dh_testdir # Add here commands to configure the package. ifneq "$(wildcard /usr/share/misc/config.sub)" "" cp -f /usr/share/misc/config.sub config.sub endif ifneq "$(wildcard /usr/share/misc/config.guess)" "" cp -f /usr/share/misc/config.guess config.guess endif ./configure --host=$(DEB_HOST_GNU_TYPE) --build=$(DEB_BUILD_GNU_TYPE) --prefix=/usr --mandir=\$${prefix}/share/man --infodir=\$${prefix}/share/info CFLAGS="$(CFLAGS)" LDFLAGS="-Wl,-z,defs" --enable-ncursesw --enable-all --enable-static build: build-stamp build-stamp: config.status dh_testdir # Add here commands to compile the package. $(MAKE) #docbook-to-man debian/partclone.sgml > partclone.1 touch $@ clean: dh_testdir dh_testroot rm -f build-stamp # Add here commands to clean up after the build process. -$(MAKE) dist clean override_dh_clean: dh_clean -X fail-mbr/fail-mbr.bin.orig install: build dh_testdir dh_testroot dh_clean -k dh_installdirs # Add here commands to install the package into debian/partclone. $(MAKE) DESTDIR=$(CURDIR)/debian/partclone prefix=/usr install # Build architecture-independent files here. binary-indep: build install # We have nothing to do by default. # Build architecture-dependent files here. binary-arch: build install dh_testdir dh_testroot dh_installchangelogs ChangeLog dh_installdocs dh_installexamples # dh_install # dh_installmenu # dh_installdebconf # dh_installlogrotate # dh_installemacsen # dh_installpam # dh_installmime # dh_python # dh_installinit # dh_installcron # dh_installinfo dh_installman dh_link dh_strip --dbg-package=partclone-dbg dh_compress dh_fixperms # dh_perl # dh_makeshlibs dh_installdeb dh_shlibdeps dh_gencontrol dh_md5sums dh_builddeb binary: binary-indep binary-arch .PHONY: build clean binary-indep binary-arch binary install partclone-0.2.86/README.Packages/debian.wheezy/000077500000000000000000000000001262102574200210055ustar00rootroot00000000000000partclone-0.2.86/README.Packages/debian.wheezy/changelog000066400000000000000000000626351262102574200226730ustar00rootroot00000000000000partclone (0.2.71) unstable; urgency=low [ Yu-Chin Tsai ] * Non-maintainer upload. * release for wheezy -- Wed, 09 Jul 2014 22:17:54 +0800 partclone (0.2.51) unstable; urgency=low * update makefile * update supported list * update process for elapsed time over 24hr * update version to 0.2.51 * update some docs -- Thomas Tsai Thu, 20 Sep 2012 17:07:41 +0800 partclone (0.2.50) unstable; urgency=low * release 0.2.49 * update control * update control * add partclone.btrfs.8 * add more detail message in image head output * add exfat * update exfat and add exfat man docs * add test for exfat * update test and size information * version 0.2.50 -- Thomas Tsai Tue, 10 Jul 2012 16:39:19 +0800 partclone (0.2.49) unstable; urgency=low * release 0.2.48 * update TODO * minor update readme * update docs * update docs * update manpage * fix quiet mode issue. The issue make partclone can't stop/finish even action is done. bug report from pille -- Thomas Tsai Tue, 10 Jul 2012 16:35:27 +0800 partclone (0.2.48) unstable; urgency=low [ Thomas Tsai ] * update debian control for vmfs-tools [ thomas ] * ignore unallocated block for vmfs [ Thomas Tsai ] * update bitmap progress * A partclone bug found when it backs up WindowsServer2008R2 (64bit) * update vmfs for some unallocated block -- Thomas Tsai Tue, 01 May 2012 11:32:47 +0800 partclone (0.2.47) unstable; urgency=low * try to fix ID: 3509757 from clonezilla track system * change row to raw, noticed from Vincent van Adrighem * update fresh, add sleep in progress thread to reduce cpu usage, contributed and bug information from http://sourceforge.net/tracker/?func=detail&aid=3509757&group_id=115473&atid=671650 * update fresh done * 0.2.47 -- Thomas Tsai Wed, 18 Apr 2012 13:41:31 +0800 partclone (0.2.46) unstable; urgency=low * accept part of patch from Matthew Booth's review * update partclone.vmfs for version 5 * update manpages * update document, some example error. * update vmfsclone to backup vmfs5 well * accept patch from Rommer to update memory usage * and release 0.2.46 -- Thomas Tsai Mon, 02 Apr 2012 09:14:23 +0800 partclone (0.2.45) unstable; urgency=low * print vmfs version from fstype * add compatibility of vmfs3 and vmfs5 -- Thomas Tsai Wed, 18 Jan 2012 10:39:22 +0800 partclone (0.2.44) unstable; urgency=low * update pui for mode dev-to-dev -- Thomas Tsai Tue, 17 Jan 2012 15:11:30 +0800 partclone (0.2.43) unstable; urgency=low * 0.2.43 -- Thomas Tsai Tue, 27 Dec 2011 16:25:57 +0800 partclone (0.2.42) unstable; urgency=low * add option B to disable block detail; old progress style. * add finish progress to dd * 0.2.42 -- Thomas Tsai Tue, 27 Dec 2011 15:58:55 +0800 partclone (0.2.41) unstable; urgency=low * add block status * update progress bar * add thread to display progress, draft * add thread to dd, restore and chkimg * 0.2.41 -- Thomas Tsai Tue, 27 Dec 2011 00:53:41 +0800 partclone (0.2.40) unstable; urgency=low * update progress seeking at 100% -- Thomas Tsai Fri, 23 Dec 2011 10:25:43 +0800 partclone (0.2.39) unstable; urgency=low * 0.2.39 * updaet ntfsfixboot to version 1.0 -- Thomas Tsai Mon, 12 Dec 2011 14:49:22 +0800 partclone (0.2.38) unstable; urgency=low * update for makefile for ncursesw * update for progress * 0.2.38 -- Thomas Tsai Mon, 12 Dec 2011 14:27:23 +0800 partclone (0.2.37) unstable; urgency=low * add -I/usr/include/ncursesw/ * release 0.2.37 -- Thomas Tsai Wed, 23 Nov 2011 16:32:09 +0800 partclone (0.2.36) unstable; urgency=low * update ncurses size * 0.2.36 -- Thomas Tsai Wed, 23 Nov 2011 16:31:06 +0800 partclone (0.2.35) unstable; urgency=low * move debian folder to README.Packages as sample * update control for debian-sid * save last changelog ($version) * update version script * add debian * re remove debian * update TODO * add debian * remove debian * add debian * move partclone.spec to README.Packages/partclone.spec * update * align version and tag * update toolbox -- Thomas Tsai Wed, 02 Nov 2011 01:07:24 +0800 partclone (0.2.34) unstable; urgency=low * update autoconf and automake for squeeze -- Thomas Tsai Tue, 01 Nov 2011 11:32:42 +0800 partclone (0.2.33) unstable; urgency=low * update makefile for ncurses static linking * update memory usage * update ncurses progress bar -- Thomas Tsai Thu, 27 Oct 2011 22:05:17 +0800 partclone (0.2.32) unstable; urgency=low * accept patch file from Rommer. * Attached patch for partclone 0.2.31 reduces memory usage by 4-8 times. by Rommer. -- Thomas Tsai Wed, 12 Oct 2011 21:27:43 +0800 partclone (0.2.31) unstable; urgency=low * update for vmfs5 -- Thomas Tsai Wed, 12 Oct 2011 21:27:43 +0800 partclone (0.2.30) unstable; urgency=low * patch for new vmfs-tools -- Thomas Tsai Tue, 11 Oct 2011 21:21:24 +0800 partclone (0.2.29) unstable; urgency=low * fix bugs * release 0.2.29 -- Thomas Tsai Mon, 12 Sep 2011 21:21:24 +0800 partclone (0.2.28) unstable; urgency=low * update e2fslibs for squeeze * fix bug for ntfsclone with ncurses on unstable -- Thomas Tsai Thu, 08 Sep 2011 22:58:27 +0800 partclone (0.2.27) unstable; urgency=low * accept patch from Georges about configure, fixIntTypes and typos in manpages * try to fix issue for bitmap, suggestion from Paul. -- Thomas Tsai Tue, 30 Aug 2011 11:45:06 +0800 partclone (0.2.26) unstable; urgency=low * update test script -- Thomas Tsai Mon, 15 Aug 2011 10:45:06 +0800 partclone (0.2.25) unstable; urgency=low * update for e2fslibs 1.42~WIP-2011-07-02 * compact ntfs and ntfs-3g -- Thomas Tsai Mon, 15 Aug 2011 10:45:06 +0800 partclone (0.2.24) natty; urgency=low * accept patch from Ian Abbott. * '--domain' (-D) and -offset_domain=X to generate domain file for ddrescue. -- Thomas Tsai Tue, 24 May 2011 10:45:06 +0800 partclone (0.2.23) maverick; urgency=low * update manpages -- Thomas Tsai Fri, 22 Apr 2011 11:02:59 +0800 partclone (0.2.22) maverick; urgency=low * typo error for progress -- Thomas Tsai Mon, 28 Mar 2011 15:19:16 +0800 partclone (0.2.21) maverick; urgency=low * fix bug for partclone.dd and partclone.restore for stdin dd data. -- Thomas Tsai Tue, 22 Mar 2011 14:21:11 +0800 partclone (0.2.20) maverick; urgency=low * fix dd issue. set default size as target size for stdin data. -- Thomas Tsai Mon, 14 Mar 2011 10:12:19 +0800 partclone (0.2.19) unstable; urgency=low * update makefile for btrf -- Thomas Tsai Wed, 09 Mar 2011 14:06:05 +0800 partclone (0.2.18) unstable; urgency=low * add option max_block_cache to get better performance escpcially small block size(fat) * update typo error -- Thomas Tsai Tue, 25 Jan 2011 16:06:05 +0800 partclone (0.2.17) unstable; urgency=low * update for ext4 metadata mismatch issue * update makefile and configure -- Thomas Tsai Tue, 25 Jan 2011 16:06:05 +0800 partclone (0.2.16) unstable; urgency=low * add option --quiet to disable progress bar * add option --restore_row_file to create special file for mounting with loop option -- Thomas Tsai Wed, 06 Oct 2010 16:06:05 +0800 partclone (0.2.15) unstable; urgency=low * Bug fixed: btrfs clone fail, lost some metadata message * Add po: add fr_FR po file from Cédric, very thanks. -- Thomas Tsai Wed, 01 Sep 2010 10:25:48 +0800 partclone (0.2.14) unstable; urgency=low * add btrfs support -- Thomas Tsai Sun, 22 Aug 2010 15:14:20 +0800 partclone (0.2.13) unstable; urgency=low * add link partclone.VMFS_volume_member * fix bug: jfsclone segfault * add debian/control pkg-config -- Thomas Tsai Wed, 28 Jul 2010 17:14:20 +0800 partclone (0.2.12) unstable; urgency=low * New Feature: The jfs filesystem is supported. -- Thomas Tsai Wed, 30 Jun 2010 11:58:41 +0800 partclone (0.2.11) unstable; urgency=low * Bug fixed: xfsclone type error for amd64 * Update control file: add libvmfs -- Thomas Tsai Wed, 19 May 2010 12:22:07 +0800 partclone (0.2.10) unstable; urgency=low * Bug fixed: chkimg.c not work * Bug fixed: new xfsclone -- Thomas Tsai Wed, 19 May 2010 12:22:07 +0800 partclone (0.2.9) unstable; urgency=low * Bug fixed: error for backup partition larger than 8.7T * Bug fixed: better memory usage for restore -- Thomas Tsai Thu, 29 Apr 2010 15:22:07 +0800 partclone (0.2.8) unstable; urgency=low * Bug fixed: update progress bar faster -- Thomas Tsai Mon, 29 Mar 2010 16:22:38 +0800 partclone (0.2.7-1) unstable; urgency=low * fix progress bug about: alwayn new line for 640x480 resolution * update version -- Thomas Tsai Tue, 16 Mar 2010 15:13:04 +0800 partclone (0.2.6-1) unstable; urgency=low * update version -- Thomas Tsai Mon, 15 Mar 2010 11:29:18 +0800 partclone (0.2.5-1) unstable; urgency=low * A bug about 0 rate for bitmap calculation. * update partclone to show more readable size for partition and rate/min. -- Thomas Tsai Fri, 12 Mar 2010 09:15:31 +0800 partclone (0.2.4-1) unstable; urgency=low * autogen git number * fix progress inf bug -- Thomas Tsai Wed, 10 Mar 2010 16:30:55 +0800 partclone (0.2.3-1) unstable; urgency=low * add partclone.fstype to test filesystem type (vmfs only) * update svn versionto git version -- Thomas Tsai Tue, 02 Mar 2010 13:50:26 +0800 partclone (0.2.0-2) unstable; urgency=low * VMFS supported in this release. -- Steven Shiau Sun, 14 Feb 2010 15:00:00 +0800 partclone (0.2.0-1) unstable; urgency=low [ Yu-Chin Tsai ] * A test release. -- Thomas Tsai Wed, 06 Jan 2010 16:07:05 +0800 partclone (0.1.9-5) unstable; urgency=low [ Yu-Chin Tsai ] * A bug about hfsplus error for 2 or more extents was fixed. -- Steven Shiau Wed, 25 Nov 2009 16:54:00 +0800 partclone (0.1.9-4) unstable; urgency=low * update configure.ac, set ufs as default enabled file system. * update progress bar to show the "100%" in the end. -- Yu-Chin Tsai Mon, 16 Nov 2009 14:46:04 +0800 partclone (0.1.9-3) unstable; urgency=low [ Yu-Chin Tsai ] * An option to ignore CRC checking was added. -- Steven Shiau Tue, 03 Nov 2009 17:16:00 +0800 partclone (0.1.9-2) unstable; urgency=low [ Yu-Chin Tsai ] * Bug fixed: update log message and open fail message for ufsclone. Thanks to dswartz for testing ufs backup and report. -- Steven Shiau Fri, 09 Oct 2009 11:14:00 +0800 partclone (0.1.9-1) unstable; urgency=low [ Yu-Chin Tsai ] * Bug fixed: XFS clone failure was fixed. * UFS was added. -- Yu-Chin Tsai Thu, 17 Sep 2009 14:07:33 +0800 partclone (0.1.1-16) unstable; urgency=low [Thomas Tsai] * Bug fixed: FAT clone failure was fixed. -- Steven Shiau Sun, 09 Aug 2009 08:49:00 +0800 partclone (0.1.1-15) unstable; urgency=low [Thomas Tsai] * Bug fixed: Wrong path for exec files. -- Steven Shiau Wed, 24 Jun 2009 16:48:00 +0800 partclone (0.1.1-14) unstable; urgency=low [Thomas Tsai] * Bug fixed: version number from SVN was not shown correctly. -- Steven Shiau Wed, 24 Jun 2009 14:36:00 +0800 partclone (0.1.1-13) unstable; urgency=low [Thomas Tsai] * Prompt messages were updated. -- Steven Shiau Fri, 18 Jun 2009 13:30:00 +0800 partclone (0.1.1-12) unstable; urgency=low [Thomas Tsai] * An option was added: --logfile or -L to specify file for log message. * A new program partclone.chkimg was added to help checking img by CRC. -- Steven Shiau Wed, 17 Jun 2009 10:34:00 +0800 partclone (0.1.1-11) unstable; urgency=low [Thomas Tsai] * update clear_buf * The patch from Kristian Erik Hermansen. fix progress.c:152- SECURITY: fprintf call should have "%s" as argument 1 -- Steven Shiau Sat, 13 Jun 2009 14:39:00 +0800 partclone (0.1.1-10) unstable; urgency=low [Thomas Tsai] * Bug fixed: pointer problem was fixed. * Bug fixed: buffer overflow problem was fixed. Thanks to Kristian Erik Hermansen and Piavlo. * Bug fixed: a bug about hfs+ was fixed. -- Steven Shiau Wed, 10 Jun 2009 10:39:00 +0800 partclone (0.1.1-9) unstable; urgency=low [Steven Shiau] * Some output messages were polished again. -- Steven Shiau Tue, 02 Jun 2009 18:09:00 +0800 partclone (0.1.1-8) unstable; urgency=low [Thomas Tsai] * Some output messages were polished. -- Steven Shiau Tue, 02 Jun 2009 16:51:00 +0800 partclone (0.1.1-7) unstable; urgency=low [Thomas Tsai] * Bug fixed: Progress update with nogui, "Calculating bitmap..." was added without option -d. -- Steven Shiau Mon, 01 Jun 2009 22:36:00 +0800 partclone (0.1.1-6) unstable; urgency=low [Thomas Tsai] * bug of CRC in 64 bit image problem was fixed. A better method will be imlemented in the nexe version of image format. -- Steven Shiau Sat, 30 May 2009 12:10:00 +0800 partclone (0.1.1-5) unstable; urgency=low [Thomas Tsai] * bug of time calculating was fixed. -- Steven Shiau Wed, 27 May 2009 22:13:00 +0800 partclone (0.1.1-4) unstable; urgency=low [Thomas Tsai] * Update default RES from 10000 to 1000. -- Steven Shiau Wed, 27 May 2009 12:59:00 +0800 partclone (0.1.1-3) unstable; urgency=low [Thomas Tsai] * Bug fixed: block device should not have to use "--overwrite". -- Steven Shiau Wed, 27 May 2009 11:23:00 +0800 partclone (0.1.1-2) unstable; urgency=low [Thomas Tsai] * partclone.ntfsreloc is linked to partclone.ntfsfixboot. -- Steven Shiau Fri, 22 May 2009 13:52:00 +0800 partclone (0.1.1-1) unstable; urgency=low [Thomas Tsai] * Minor updates for output messages. * New Feature: add argument to set fresh of progress bar * New Feature: restore to new file(non-block device) * A bug about crc check in 64bit image * Update partclone.ntfsreloc to ntfsfixboot.c from http://cc.jct.ac.il/~shaneh/ntfsfixboot.c -- root Fri, 22 May 2009 05:52:00 +0800 partclone (0.1.0-10) unstable; urgency=low [ Thomas Tsai ] * Bug fixed: clonezilla-Bugs-2784676. Thanks to njorl _at_ users sourceforge net. -- Steven Shiau Fri, 01 May 2009 10:55:00 +0800 partclone (0.1.0-9) unstable; urgency=low [ Steven Shiau ] * Minor updates for output messages. -- Steven Shiau Sun, 26 Apr 2009 13:54:00 +0800 partclone (0.1.0-8) unstable; urgency=low [ Steven Shiau ] * Minor updates for output messages. [ Thomas Tsai ] * EXECNAME was added for partclone.restore. -- Steven Shiau Fri, 24 Apr 2009 14:07:00 +0800 partclone (0.1.0-7) unstable; urgency=low [ Thomas Tsai ] * partclone.ext4dev is linkded now. -- Steven Shiau Thu, 23 Apr 2009 19:01:00 +0800 partclone (0.1.0-6) unstable; urgency=low [ Thomas Tsai ] * A bug about partclone.restore used to restore known file systems was fixed. -- Steven Shiau Thu, 18 Apr 2009 09:59:00 +0800 partclone (0.1.0-5) unstable; urgency=low [ Thomas Tsai ] * A bug about checking partition size was fixed. -- Steven Shiau Thu, 16 Apr 2009 15:03:00 +0800 partclone (0.1.0-4) unstable; urgency=low [ Thomas Tsai ] * Local device to device copy mode option "-b, --dd-mode" was changed to be "-b, --dev-to-dev" * A bug about partclone.dd wrongly get the partition size was fixed. -- Steven Shiau Thu, 16 Apr 2009 12:16:00 +0800 partclone (0.1.0-3) unstable; urgency=low [ Thomas Tsai ] * Bug fixed: partclone.ntfs statistics data was wrong when doing partition to partition clone. -- Steven Shiau Tue, 15 Apr 2009 10:52:00 +0800 partclone (0.1.0-2) unstable; urgency=low [ Steven Shiau ] * --enable-static is on again. -- Steven Shiau Tue, 10 Apr 2009 11:47:00 +0800 partclone (0.1.0-1) unstable; urgency=low [ Thomas Tsai ] * partclone.ext4, partclone.dd, partclone.restore were added. -- Steven Shiau Tue, 07 Apr 2009 15:01:00 +0800 partclone (0.0.9-4) unstable; urgency=low [ Thomas Tsai ] * A bug about FAT12 was fixed. -- Steven Shiau Tue, 30 Dec 2008 13:41:00 +0800 partclone (0.0.9-3) unstable; urgency=low [ Steven Shiau ] * New upstream ntfsreloc.c 0.8. -- Steven Shiau Thu, 25 Dec 2008 15:32:00 +0800 partclone (0.0.9-2) unstable; urgency=low [ Thomas Tsai ] * Update dirty message for ntfsclone-ng. * Check filesystem before cloning partition. Partclone will make sure that. * Add check hfs_plus filesystem before cloning volume. * Update fatclone.c fatclone.h clearly. update dirty message for extfs. -- Steven Shiau Mon, 22 Dec 2008 09:46:00 +0800 partclone (0.0.9-1) unstable; urgency=low # New features: partclone.ntfsreloc and partclone.ntfs were added. -- Steven Shiau Thu, 30 Oct 2008 10:51:00 +0800 partclone (0.0.8-8) unstable; urgency=low # Bug fixed: Failing to restore fat32 image was fixed by Thomas Tsai. -- Steven Shiau Wed, 30 Jul 2008 09:18:00 +0800 partclone (0.0.8-7) unstable; urgency=low # partclone.hfsplus link was added by Thomas Tsai. -- Steven Shiau Thu, 24 Jul 2008 11:53:00 +0800 partclone (0.0.8-6) unstable; urgency=low # Bug fixed: partclone.fat12 link was not done. -- Steven Shiau Fri, 11 Jul 2008 16:11:00 +0800 partclone (0.0.8-5) unstable; urgency=low # fat12 was added by Thomas Tsai. -- Steven Shiau Fri, 11 Jul 2008 15:03:00 +0800 partclone (0.0.8-4) unstable; urgency=low # Enable static linking. -- Steven Shiau Sat, 28 Jun 2008 10:22:00 +0800 partclone (0.0.8-3) unstable; urgency=low # Some minor updates about messages by Thomas Tsai. -- Steven Shiau Sun, 15 Jun 2008 22:48:00 +0800 partclone (0.0.8-2) unstable; urgency=low # configure.ac updated by Thomas Tsai. # partclone website is www.partclone.org now. -- Steven Shiau Mon, 26 May 2008 14:19:00 +0800 partclone (0.0.8-1) unstable; urgency=low # clone.$FS was renamed as partclone.$FS by Thomas Tsai. -- Steven Shiau Sun, 25 May 2008 09:19:00 +0800 partclone (0.0.7-4) unstable; urgency=low # Some bugs about ncursesw were fixed by Thomas Tsai. -- Steven Shiau Fri, 16 May 2008 16:18:00 +0800 partclone (0.0.7-3) unstable; urgency=low # Some bugs about ncursesw were fixed by Thomas Tsai. -- Steven Shiau Thu, 06 May 2008 23:00:00 +0800 partclone (0.0.7-2) unstable; urgency=low # Use --enable-ncursesw by default. -- Steven Shiau Thu, 01 May 2008 11:13:00 +0800 partclone (0.0.7-1) unstable; urgency=low # New functions: TUI mode for output done by Thomas Tsai. -- Steven Shiau Thu, 01 May 2008 11:08:00 +0800 partclone (0.0.6-4) unstable; urgency=low # Some new function for #14 "TUI of status reports" from Thomas Tsai. # Smaller FS_MAGIC_SIZE in main.c. -- Steven Shiau Tue, 22 Apr 2008 14:52:00 +0800 partclone (0.0.6-3) unstable; urgency=low # Bug fixed: version was not changed. -- Steven Shiau Thu, 21 Feb 2008 13:40:00 +0800 partclone (0.0.6-2) unstable; urgency=low # Bug fixed: clone.fat was not complied. -- Steven Shiau Wed, 20 Feb 2008 22:47:00 +0800 partclone (0.0.6-1) unstable; urgency=low # clone.fat was added by Thomas Tsai. -- Steven Shiau Wed, 20 Feb 2008 22:41:00 +0800 partclone (0.0.5-16) unstable; urgency=low # Typos fixed. # Bug fixed: partition to partition clone size checking failed. -- Steven Shiau Sat, 16 Feb 2008 10:02:00 +0800 partclone (0.0.5-15) unstable; urgency=low # partclone.nchc.org.tw was put without http:// in usage. -- Steven Shiau Mon, 04 Feb 2008 13:47:00 +0800 partclone (0.0.5-14) unstable; urgency=low # Some minor bugs fixed by Thomas Tsai. # http://partclone.nchc.org.tw was added in usage. -- Steven Shiau Mon, 04 Feb 2008 13:45:00 +0800 partclone (0.0.5-13) unstable; urgency=low * Bugs fixed and feature added by Thomas Tsai: # reduce seek time # fix number of Ave.Rate # check every filesystem's image_head data... # add new option to disable device and free space checking -- Steven Shiau Tue, 30 Jan 2008 23:07:00 +0800 partclone (0.0.5-12) unstable; urgency=low * Bug fixed by Thomas Tsai: Partition size checking failed in some cases. -- Steven Shiau Tue, 30 Jan 2008 21:08:00 +0800 partclone (0.0.5-11) unstable; urgency=low * Bug fixed by Thomas Tsai: Partition size checking failed -- Steven Shiau Tue, 29 Jan 2008 16:47:00 +0800 partclone (0.0.5-10) unstable; urgency=low * Functions to check memory size, check_free_space were added by Thomas Tsai. -- Steven Shiau Wed, 23 Jan 2008 22:57:00 +0800 partclone (0.0.5-9) unstable; urgency=low * Thomas Tsai added: New function rescue_sector. UNSTALBE feature, support device to device. Some other minor changes. -- Steven Shiau Sun, 20 Jan 2008 14:15:00 +0800 partclone (0.0.5-8) unstable; urgency=low * Some minor changes on ticket #18 from Thomas Tsai. -- Steven Shiau Fri, 11 Jan 2008 09:24:00 +0800 partclone (0.0.5-7) unstable; urgency=low * Some minor changes. -- Steven Shiau Wed, 9 Jan 2008 22:45:00 +0800 partclone (0.0.5-6) unstable; urgency=low * Thomas Tsai enhanced the status report. -- Steven Shiau Wed, 9 Jan 2008 09:15:00 +0800 partclone (0.0.5-5) unstable; urgency=low * Thomas Tsai closed ticket #18: Add a saving/restoring rate and estimated time to finish job in the status report. -- Steven Shiau Sun, 8 Jan 2008 15:12:00 +0800 partclone (0.0.5-4) unstable; urgency=low * Thomas Tsai closed these tickets: #12: Command without any option should show only short help messages. #13: Change "HFSPLUS" as "HFS+" or "HFS Plus". #15 (Sync after image is restored). #17: Show program name "partclone" and version number and url in the status report. -- Steven Shiau Sun, 7 Jan 2008 17:05:00 +0800 partclone (0.0.5-3) unstable; urgency=low * Static linking was disabled in debian/rules. -- Steven Shiau Sun, 6 Jan 2008 16:34:00 +0800 partclone (0.0.5-2) unstable; urgency=low * Description for deb package was updated. -- Steven Shiau Fri, 4 Jan 2008 21:40:00 +0800 partclone (0.0.5-1) unstable; urgency=low * [bugfix] reopen and close ticket #8 - fix debian packaging linking permission issue. -- Jazz Yao-Tsung Wang Fri, 4 Jan 2008 11:54:14 +0800 partclone (0.0.4-5) unstable; urgency=low * close ticket #8. Thomas added some alias programs when making install. -- Steven Shiau Fri, 4 Jan 2008 11:12:00 +0800 partclone (0.0.4-3ubuntu1) feisty; urgency=low * add support of static linking to configure.ac and src/Makefile.am * [BUGFIX #1] fixed static linking time error while enabling XFS file system support. * modified debian packaginf control and rules to fix some mistakes. -- Jazz Yao-Tsung Wang Wed, 2 Jan 2008 21:23:52 +0800 partclone (0.0.4-3) unstable; urgency=low * A Bug about restoring image from stdin was fixed by Jazz Wang. * zh_TW.po was updated. -- Steven Shiau Sun, 1 Jan 2008 20:20:00 +0800 partclone (0.0.4-2) unstable; urgency=low * Updated config by Jazz Wang so that static linking now it's better. Not finished. * Help messages updated. -- Steven Shiau Sun, 1 Jan 2008 11:20:00 +0800 partclone (0.0.4-1) unstable; urgency=low * Initial release. * modify rules -- Yu-Chin Tsai Thu, 13 Dec 2007 10:48:03 +0800 partclone-0.2.86/README.Packages/debian.wheezy/compat000066400000000000000000000000021262102574200222030ustar00rootroot000000000000009 partclone-0.2.86/README.Packages/debian.wheezy/control000066400000000000000000000024641262102574200224160ustar00rootroot00000000000000Source: partclone Section: admin Priority: extra Maintainer: Yu-Chin Tsai Build-Depends: debhelper (>= 9), dpkg-dev (>= 1.16.1~), dh-autoreconf, autotools-dev, pkg-config, xsltproc, docbook-xsl, docbook-xml, libncursesw5-dev, libtinfo-dev, e2fslibs-dev (>= 1.41.3), libbsd-dev, ntfs-3g-dev|libntfs-dev, xfslibs-dev, libreiserfs0.3-dev, libreiser4-dev, libufs2 (>= 7.2), libvmfs (>= 0.2.5), libjfs-dev, libblkid-dev, uuid-dev, nilfs-tools Standards-Version: 3.9.3 Package: partclone Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} Description: Utility to clone and restore a partition. This project like the well-known backup utility "Partition Image" a.k.a partimage. . Partclone provides utilities to back up used blocks and design for higher compatibility of the file system using supported library like e2fslibs. . check the project website for more details http://partclone.org Package: partclone-dbg Section: debug Priority: extra Architecture: any Depends: ${misc:Depends}, partclone (= ${binary:Version}) Description: Utility to clone and restore a partition for debug. This project like the well-known backup utility "Partition Image" a.k.a partimage. . This package contains the debugging symbols. . check the project website for more details http://partclone.org partclone-0.2.86/README.Packages/debian.wheezy/copyright000066400000000000000000000067701262102574200227520ustar00rootroot00000000000000Format: http://dep.debian.net/deps/dep5 Upstream-Name: partclone Upstream-Contact: Yu-Chin Tsai Source: https://github.com/Thomas-Tsai/partclone Files: * Copyright: 2006-2012 Thomas Tsai 2007-2012 Steven Shiau 2007-2008 Jazz Wang License: GPL-2+ see below for the text of this license. Files: debian/* Copyright: 2012 Thomas Tsai 2011 Georges Khaznadar License: GPL-2+ see below for the text of this license. Files: src/ufs/libufs.h Copyright: 2002 Juli Mallett License: FreeBSD-like see below for the text of this license. Files: src/ufs/sys/* Copyright: 1987, 1988, 1993 The Regents of the University of California. License: FreeBSD-like see below for the text of this license. Files: src/ufs/ffs/* Copyright: 1982, 1986, 1993 The Regents of the University of California. License: FreeBSD-like see below for the text of this license. Files: src/ufs/ufs/fs.h Copyright: 1982, 1986, 1993 The Regents of the University of California. License: FreeBSD-like see below for the text of this license. Files: src/ufs/ufs/dinode.h Copyright: 2002 Networks Associates Technology, Inc. License: FreeBSD-like see below for the text of this license. License: FreeBSD-like Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 4. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. . THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. License: GPL-2+ This package is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. . This package is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. . You should have received a copy of the GNU General Public License along with this program. If not, see . On Debian systems, the complete text of the GNU General Public License version 2 can be found in "/usr/share/common-licenses/GPL-2". partclone-0.2.86/README.Packages/debian.wheezy/dirs000066400000000000000000000000111262102574200216610ustar00rootroot00000000000000usr/sbin partclone-0.2.86/README.Packages/debian.wheezy/docs000066400000000000000000000000171262102574200216560ustar00rootroot00000000000000NEWS README.md partclone-0.2.86/README.Packages/debian.wheezy/rules000077500000000000000000000026201262102574200220650ustar00rootroot00000000000000#!/usr/bin/make -f # -*- makefile -*- # Sample debian/rules that uses debhelper. # This file was originally written by Joey Hess and Craig Small. # As a special exception, when this file is copied by dh-make into a # dh-make output file, you may use that output file without restriction. # This special exception was added by Craig Small in version 0.37 of dh-make. # Uncomment this to turn on verbose mode. export DH_VERBOSE=1 DPKG_EXPORT_BUILDFLAGS = 1 include /usr/share/dpkg/buildflags.mk %: dh $@ --with autoreconf --with autotools-dev override_dh_auto_configure: # Add here commands to configure the package. #cp /usr/share/misc/config.sub . #cp /usr/share/misc/config.guess . #autoreconf #./configure --prefix=/usr --mandir=\$${prefix}/share/man --infodir=\$${prefix}/share/info LDFLAGS="-Wl,-z,defs" --enable-ncursesw --enable-extfs --enable-static # dh_auto_configure -- --enable-ncursesw --enable-extfs --enable-static # for normal linux dh_auto_configure -- --enable-ncursesw --enable-all --enable-static # for clonezilla dist override_dh_auto_install: $(MAKE) DESTDIR=$$(pwd)/debian/partclone prefix=/usr install override_dh_auto_clean: dh_auto_clean rm -f get_lib_version rm -f config.sub configure Makefile.in aclocal.m4 config.guess rm -f src/Makefile.in docs/Makefile.in override_dh_clean: dh_clean -X fail-mbr/fail-mbr.bin.orig override_dh_strip: dh_strip --dbg-package=partclone-dbg partclone-0.2.86/README.Packages/debian.wheezy/source/000077500000000000000000000000001262102574200223055ustar00rootroot00000000000000partclone-0.2.86/README.Packages/debian.wheezy/source/format000066400000000000000000000000141262102574200235130ustar00rootroot000000000000003.0 (quilt) partclone-0.2.86/README.Packages/debian/000077500000000000000000000000001262102574200174735ustar00rootroot00000000000000partclone-0.2.86/README.Packages/debian/changelog000066400000000000000000001014551262102574200213530ustar00rootroot00000000000000partclone (0.2.86-1) unstable; urgency=medium * add zh_CN language support * fix fat cluster count issue * fix nilfs mount issue -- Thomas Tsai Thu, 12 Nov 2015 14:04:16 +0800 partclone (0.2.85-1) unstable; urgency=medium * update configure.ac for ntfs check * fix fat 16 clone issue * add fat 12, fat 16 and fat 32 test script -- Thomas Tsai Thu, 12 Nov 2015 11:43:14 +0800 partclone (0.2.84-1) unstable; urgency=medium * add nilfs2 support * add xfs as build-in api * minor update for tests, configure... -- Thomas Tsai Tue, 13 Oct 2015 14:27:51 +0800 partclone (0.2.83-1) unstable; urgency=medium * update xfs bitmap calculating time -- Thomas Tsai Mon, 24 Aug 2015 14:56:24 +0800 partclone (0.2.82-1) unstable; urgency=medium * fix 4k and ditry bitmap for xfs -- Thomas Tsai Mon, 24 Aug 2015 09:54:45 +0800 partclone (0.2.81-1) unstable; urgency=medium * chanhe ncurses update -- Thomas Tsai Thu, 23 Jul 2015 16:14:37 +0800 partclone (0.2.80-1) unstable; urgency=medium * fix vmfs and ncursesw issue -- Thomas Tsai Tue, 21 Jul 2015 14:12:24 +0800 partclone (0.2.79-1) unstable; urgency=medium * fix vmfs issue -- Thomas Tsai Wed, 01 Jul 2015 13:39:39 +0800 partclone (0.2.78-1) unstable; urgency=medium * fix extfs clone issue * fix partition over than 16T issue -- Thomas Tsai Thu, 09 Apr 2015 16:02:57 +0800 partclone (0.2.77-1) unstable; urgency=medium * fix btrfs clone fail on bitmap check -- Thomas Tsai Wed, 25 Mar 2015 10:08:02 +0800 partclone (0.2.76-1) unstable; urgency=medium * fix xfs issue * accept patch about badblocks -- Thomas Tsai Fri, 16 Jan 2015 10:56:53 +0800 partclone (0.2.75-1) unstable; urgency=medium * fix btrfs issue -- Thomas Tsai Tue, 30 Dec 2014 10:22:48 +0800 partclone (0.2.74-1) unstable; urgency=medium * fix makefile for failmbr * fix crosscompile issue * add option --note -- Thomas Tsai Wed, 05 Nov 2014 15:56:18 +0800 partclone (0.2.73-1) unstable; urgency=medium * upgrade exfat * add f2fs support * some minner fix * release 0.2.73 as current testing version -- Thomas Tsai Fri, 05 Sep 2014 10:46:26 +0800 partclone (0.3.0~gitbcaa-1) unstable; urgency=medium * fix dd error -- Thomas Tsai Wed, 03 Sep 2014 16:33:13 +0800 partclone (0.3.0~git526b-1) unstable; urgency=medium * merge relese to master * first release new image format of partclone -- Thomas Tsai Wed, 03 Sep 2014 15:18:56 +0800 partclone (0.2.73~git0ded-1) unstable; urgency=medium * upgrade exfat to 1.1.0 -- Thomas Tsai Wed, 03 Sep 2014 11:05:23 +0800 partclone (0.2.73~gitbb99-1) unstable; urgency=medium * unstable package and test f2fs -- Thomas Tsai Wed, 03 Sep 2014 10:13:26 +0800 partclone (0.2.72-1) unstable; urgency=medium * add README.Packages/* to support debian sid, jessie and wheezy -- Thomas Tsai Tue, 15 Jul 2014 10:43:52 +0800 partclone (0.2.71-1) unstable; urgency=medium * fix xfs to 3.2.0 * add libblkid-dev check -- Thomas Tsai Tue, 08 Jul 2014 10:55:22 +0800 partclone (0.2.70-1) unstable; urgency=low * fix option 'restore_raw_file' -- Thomas Tsai Mon, 20 Jan 2014 16:43:07 +0800 partclone (0.2.69-1) unstable; urgency=low * update reiser4 bug * update tests/script -- Thomas Tsai Thu, 26 Dec 2013 15:17:14 +0800 partclone (0.2.68-1) unstable; urgency=low * update rules for squeeze * add stdin support for partclone.info * fix static link error for partclone.xfs -- Thomas Tsai Mon, 09 Dec 2013 14:33:26 +0800 partclone (0.2.67-1) unstable; urgency=low * update btrfs clone * update manual * update failmbr/makefile for archlinux -- Thomas Tsai Mon, 02 Dec 2013 17:36:06 +0800 partclone (0.2.66-1) unstable; urgency=low * fix stdin size smaller than buffer size for partclone.dd -- Thomas Tsai Wed, 03 Jul 2013 01:27:03 +0800 partclone (0.2.65-1) unstable; urgency=low * fix open error for partclone.dd -- Thomas Tsai Tue, 02 Jul 2013 01:01:38 +0800 partclone (0.2.64-1) unstable; urgency=low * rewrite partclone.dd * fix stdin for partclone.dd * fix check target size for partclone.dd -- Thomas Tsai Mon, 01 Jul 2013 14:30:05 +0800 partclone (0.2.63-1) unstable; urgency=low * fix partclone.dd, generate real dd file * add partclone.imager, generate partclone style image file -- Thomas Tsai Sun, 30 Jun 2013 10:33:23 +0800 partclone (0.2.62-1) unstable; urgency=low * update jfs issue * update crc * add po -- Thomas Tsai Tue, 18 Jun 2013 14:52:41 +0800 partclone (0.2.61-1) unstable; urgency=low * add option -z to config buffer size (default 1048576) * accept patch from Роман Шишнев to fix: cpu usage, and duplicate code. * remove option -m * find a lot of warning from -Wall and fix it. -- Thomas Tsai Mon, 20 May 2013 17:19:12 +0800 partclone (0.2.60-1) unstable; urgency=low * make exfat back -- Thomas Tsai Thu, 28 Mar 2013 23:54:21 +0800 partclone (0.2.60-1) unstable; urgency=low * make exfat back -- Thomas Tsai Thu, 28 Mar 2013 23:45:19 +0800 partclone (0.2.59-1) unstable; urgency=low * add minix support * add option -w, --skip_write_error to skip write error while restore partition. -- Thomas Tsai Thu, 21 Feb 2013 13:57:19 +0800 partclone (0.2.58-1) unstable; urgency=low * text mode for small resolution * change path of fallmbr -- Thomas Tsai Tue, 22 Jan 2013 10:03:05 +0800 partclone (0.2.57-1) unstable; urgency=low * fix jfs clone issue * add failmbr -- Yu-Chin Tsai Mon, 14 Jan 2013 17:21:39 +0800 partclone (0.2.56) unstable; urgency=low * release 0.2.56 * add Restore to offset // check github issue #1 * Fix problems reported by cppcheck //github #4 * Add malloc/calloc result check // github #3 -- Yu-Chin Tsai Tue, 06 Nov 2012 11:07:54 +0800 partclone (0.2.55-1) unstable; urgency=low * fix bug vmfs3 and log information * thanks Masayuki Moriyama report these two bugs and patchs -- Yu-Chin Tsai Thu, 11 Oct 2012 16:02:50 +0800 partclone (0.2.54-1) unstable; urgency=low * fix bug from sourceforge track system about vmfs3 and log file -- Yu-Chin Tsai Mon, 08 Oct 2012 23:07:18 +0800 partclone (0.2.54-1) unstable; urgency=low * upgrade btrfs version (still 0.19 accept patches from debian source) * add --enable-fs-test to run file system clone/restore test suite * add dd test as default test * versioin 0.2.54 -- Yu-Chin Tsai Mon, 01 Oct 2012 14:07:12 +0800 partclone (0.2.53-1) unstable; urgency=low * add debian.squeeze for centos * 0.2.53-1 * add test suit -- Yu-Chin Tsai Tue, 25 Sep 2012 16:27:14 +0800 partclone (0.2.52-1) unstable; urgency=low * update debian control * update TODO * update ncurses interface. * add man page of partclone.ntfsfixboot -- Yu-Chin Tsai Fri, 21 Sep 2012 09:59:32 +0800 partclone (0.2.51) unstable; urgency=low * update makefile * update supported list * update process for elapsed time over 24hr * update version to 0.2.51 * update some docs -- Thomas Tsai Thu, 20 Sep 2012 17:07:41 +0800 partclone (0.2.50) unstable; urgency=low * release 0.2.49 * update control * update control * add partclone.btrfs.8 * add more detail message in image head output * add exfat * update exfat and add exfat man docs * add test for exfat * update test and size information * version 0.2.50 -- Thomas Tsai Tue, 10 Jul 2012 16:39:19 +0800 partclone (0.2.49) unstable; urgency=low * release 0.2.48 * update TODO * minor update readme * update docs * update docs * update manpage * fix quiet mode issue. The issue make partclone can't stop/finish even action is done. bug report from pille -- Thomas Tsai Tue, 10 Jul 2012 16:35:27 +0800 partclone (0.2.48) unstable; urgency=low [ Thomas Tsai ] * update debian control for vmfs-tools [ thomas ] * ignore unallocated block for vmfs [ Thomas Tsai ] * update bitmap progress * A partclone bug found when it backs up WindowsServer2008R2 (64bit) * update vmfs for some unallocated block -- Thomas Tsai Tue, 01 May 2012 11:32:47 +0800 partclone (0.2.47) unstable; urgency=low * try to fix ID: 3509757 from clonezilla track system * change row to raw, noticed from Vincent van Adrighem * update fresh, add sleep in progress thread to reduce cpu usage, contributed and bug information from http://sourceforge.net/tracker/?func=detail&aid=3509757&group_id=115473&atid=671650 * update fresh done * 0.2.47 -- Thomas Tsai Wed, 18 Apr 2012 13:41:31 +0800 partclone (0.2.46) unstable; urgency=low * accept part of patch from Matthew Booth's review * update partclone.vmfs for version 5 * update manpages * update document, some example error. * update vmfsclone to backup vmfs5 well * accept patch from Rommer to update memory usage * and release 0.2.46 -- Thomas Tsai Mon, 02 Apr 2012 09:14:23 +0800 partclone (0.2.45) unstable; urgency=low * print vmfs version from fstype * add compatibility of vmfs3 and vmfs5 -- Thomas Tsai Wed, 18 Jan 2012 10:39:22 +0800 partclone (0.2.44) unstable; urgency=low * update pui for mode dev-to-dev -- Thomas Tsai Tue, 17 Jan 2012 15:11:30 +0800 partclone (0.2.43) unstable; urgency=low * 0.2.43 -- Thomas Tsai Tue, 27 Dec 2011 16:25:57 +0800 partclone (0.2.42) unstable; urgency=low * add option B to disable block detail; old progress style. * add finish progress to dd * 0.2.42 -- Thomas Tsai Tue, 27 Dec 2011 15:58:55 +0800 partclone (0.2.41) unstable; urgency=low * add block status * update progress bar * add thread to display progress, draft * add thread to dd, restore and chkimg * 0.2.41 -- Thomas Tsai Tue, 27 Dec 2011 00:53:41 +0800 partclone (0.2.40) unstable; urgency=low * update progress seeking at 100% -- Thomas Tsai Fri, 23 Dec 2011 10:25:43 +0800 partclone (0.2.39) unstable; urgency=low * 0.2.39 * updaet ntfsfixboot to version 1.0 -- Thomas Tsai Mon, 12 Dec 2011 14:49:22 +0800 partclone (0.2.38) unstable; urgency=low * update for makefile for ncursesw * update for progress * 0.2.38 -- Thomas Tsai Mon, 12 Dec 2011 14:27:23 +0800 partclone (0.2.37) unstable; urgency=low * add -I/usr/include/ncursesw/ * release 0.2.37 -- Thomas Tsai Wed, 23 Nov 2011 16:32:09 +0800 partclone (0.2.36) unstable; urgency=low * update ncurses size * 0.2.36 -- Thomas Tsai Wed, 23 Nov 2011 16:31:06 +0800 partclone (0.2.35) unstable; urgency=low * move debian folder to README.Packages as sample * update control for debian-sid * save last changelog ($version) * update version script * add debian * re remove debian * update TODO * add debian * remove debian * add debian * move partclone.spec to README.Packages/partclone.spec * update * align version and tag * update toolbox -- Thomas Tsai Wed, 02 Nov 2011 01:07:24 +0800 partclone (0.2.34) unstable; urgency=low * update autoconf and automake for squeeze -- Thomas Tsai Tue, 01 Nov 2011 11:32:42 +0800 partclone (0.2.33) unstable; urgency=low * update makefile for ncurses static linking * update memory usage * update ncurses progress bar -- Thomas Tsai Thu, 27 Oct 2011 22:05:17 +0800 partclone (0.2.32) unstable; urgency=low * accept patch file from Rommer. * Attached patch for partclone 0.2.31 reduces memory usage by 4-8 times. by Rommer. -- Thomas Tsai Wed, 12 Oct 2011 21:27:43 +0800 partclone (0.2.31) unstable; urgency=low * update for vmfs5 -- Thomas Tsai Wed, 12 Oct 2011 21:27:43 +0800 partclone (0.2.30) unstable; urgency=low * patch for new vmfs-tools -- Thomas Tsai Tue, 11 Oct 2011 21:21:24 +0800 partclone (0.2.29) unstable; urgency=low * fix bugs * release 0.2.29 -- Thomas Tsai Mon, 12 Sep 2011 21:21:24 +0800 partclone (0.2.28) unstable; urgency=low * update e2fslibs for squeeze * fix bug for ntfsclone with ncurses on unstable -- Thomas Tsai Thu, 08 Sep 2011 22:58:27 +0800 partclone (0.2.27) unstable; urgency=low * accept patch from Georges about configure, fixIntTypes and typos in manpages * try to fix issue for bitmap, suggestion from Paul. -- Thomas Tsai Tue, 30 Aug 2011 11:45:06 +0800 partclone (0.2.26) unstable; urgency=low * update test script -- Thomas Tsai Mon, 15 Aug 2011 10:45:06 +0800 partclone (0.2.25) unstable; urgency=low * update for e2fslibs 1.42~WIP-2011-07-02 * compact ntfs and ntfs-3g -- Thomas Tsai Mon, 15 Aug 2011 10:45:06 +0800 partclone (0.2.24) natty; urgency=low * accept patch from Ian Abbott. * '--domain' (-D) and -offset_domain=X to generate domain file for ddrescue. -- Thomas Tsai Tue, 24 May 2011 10:45:06 +0800 partclone (0.2.23) maverick; urgency=low * update manpages -- Thomas Tsai Fri, 22 Apr 2011 11:02:59 +0800 partclone (0.2.22) maverick; urgency=low * typo error for progress -- Thomas Tsai Mon, 28 Mar 2011 15:19:16 +0800 partclone (0.2.21) maverick; urgency=low * fix bug for partclone.dd and partclone.restore for stdin dd data. -- Thomas Tsai Tue, 22 Mar 2011 14:21:11 +0800 partclone (0.2.20) maverick; urgency=low * fix dd issue. set default size as target size for stdin data. -- Thomas Tsai Mon, 14 Mar 2011 10:12:19 +0800 partclone (0.2.19) unstable; urgency=low * update makefile for btrf -- Thomas Tsai Wed, 09 Mar 2011 14:06:05 +0800 partclone (0.2.18) unstable; urgency=low * add option max_block_cache to get better performance escpcially small block size(fat) * update typo error -- Thomas Tsai Tue, 25 Jan 2011 16:06:05 +0800 partclone (0.2.17) unstable; urgency=low * update for ext4 metadata mismatch issue * update makefile and configure -- Thomas Tsai Tue, 25 Jan 2011 16:06:05 +0800 partclone (0.2.16) unstable; urgency=low * add option --quiet to disable progress bar * add option --restore_row_file to create special file for mounting with loop option -- Thomas Tsai Wed, 06 Oct 2010 16:06:05 +0800 partclone (0.2.15) unstable; urgency=low * Bug fixed: btrfs clone fail, lost some metadata message * Add po: add fr_FR po file from Cédric, very thanks. -- Thomas Tsai Wed, 01 Sep 2010 10:25:48 +0800 partclone (0.2.14) unstable; urgency=low * add btrfs support -- Thomas Tsai Sun, 22 Aug 2010 15:14:20 +0800 partclone (0.2.13) unstable; urgency=low * add link partclone.VMFS_volume_member * fix bug: jfsclone segfault * add debian/control pkg-config -- Thomas Tsai Wed, 28 Jul 2010 17:14:20 +0800 partclone (0.2.12) unstable; urgency=low * New Feature: The jfs filesystem is supported. -- Thomas Tsai Wed, 30 Jun 2010 11:58:41 +0800 partclone (0.2.11) unstable; urgency=low * Bug fixed: xfsclone type error for amd64 * Update control file: add libvmfs -- Thomas Tsai Wed, 19 May 2010 12:22:07 +0800 partclone (0.2.10) unstable; urgency=low * Bug fixed: chkimg.c not work * Bug fixed: new xfsclone -- Thomas Tsai Wed, 19 May 2010 12:22:07 +0800 partclone (0.2.9) unstable; urgency=low * Bug fixed: error for backup partition larger than 8.7T * Bug fixed: better memory usage for restore -- Thomas Tsai Thu, 29 Apr 2010 15:22:07 +0800 partclone (0.2.8) unstable; urgency=low * Bug fixed: update progress bar faster -- Thomas Tsai Mon, 29 Mar 2010 16:22:38 +0800 partclone (0.2.7-1) unstable; urgency=low * fix progress bug about: alwayn new line for 640x480 resolution * update version -- Thomas Tsai Tue, 16 Mar 2010 15:13:04 +0800 partclone (0.2.6-1) unstable; urgency=low * update version -- Thomas Tsai Mon, 15 Mar 2010 11:29:18 +0800 partclone (0.2.5-1) unstable; urgency=low * A bug about 0 rate for bitmap calculation. * update partclone to show more readable size for partition and rate/min. -- Thomas Tsai Fri, 12 Mar 2010 09:15:31 +0800 partclone (0.2.4-1) unstable; urgency=low * autogen git number * fix progress inf bug -- Thomas Tsai Wed, 10 Mar 2010 16:30:55 +0800 partclone (0.2.3-1) unstable; urgency=low * add partclone.fstype to test filesystem type (vmfs only) * update svn versionto git version -- Thomas Tsai Tue, 02 Mar 2010 13:50:26 +0800 partclone (0.2.0-2) unstable; urgency=low * VMFS supported in this release. -- Steven Shiau Sun, 14 Feb 2010 15:00:00 +0800 partclone (0.2.0-1) unstable; urgency=low [ Yu-Chin Tsai ] * A test release. -- Thomas Tsai Wed, 06 Jan 2010 16:07:05 +0800 partclone (0.1.9-5) unstable; urgency=low [ Yu-Chin Tsai ] * A bug about hfsplus error for 2 or more extents was fixed. -- Steven Shiau Wed, 25 Nov 2009 16:54:00 +0800 partclone (0.1.9-4) unstable; urgency=low * update configure.ac, set ufs as default enabled file system. * update progress bar to show the "100%" in the end. -- Yu-Chin Tsai Mon, 16 Nov 2009 14:46:04 +0800 partclone (0.1.9-3) unstable; urgency=low [ Yu-Chin Tsai ] * An option to ignore CRC checking was added. -- Steven Shiau Tue, 03 Nov 2009 17:16:00 +0800 partclone (0.1.9-2) unstable; urgency=low [ Yu-Chin Tsai ] * Bug fixed: update log message and open fail message for ufsclone. Thanks to dswartz for testing ufs backup and report. -- Steven Shiau Fri, 09 Oct 2009 11:14:00 +0800 partclone (0.1.9-1) unstable; urgency=low [ Yu-Chin Tsai ] * Bug fixed: XFS clone failure was fixed. * UFS was added. -- Yu-Chin Tsai Thu, 17 Sep 2009 14:07:33 +0800 partclone (0.1.1-16) unstable; urgency=low [Thomas Tsai] * Bug fixed: FAT clone failure was fixed. -- Steven Shiau Sun, 09 Aug 2009 08:49:00 +0800 partclone (0.1.1-15) unstable; urgency=low [Thomas Tsai] * Bug fixed: Wrong path for exec files. -- Steven Shiau Wed, 24 Jun 2009 16:48:00 +0800 partclone (0.1.1-14) unstable; urgency=low [Thomas Tsai] * Bug fixed: version number from SVN was not shown correctly. -- Steven Shiau Wed, 24 Jun 2009 14:36:00 +0800 partclone (0.1.1-13) unstable; urgency=low [Thomas Tsai] * Prompt messages were updated. -- Steven Shiau Fri, 18 Jun 2009 13:30:00 +0800 partclone (0.1.1-12) unstable; urgency=low [Thomas Tsai] * An option was added: --logfile or -L to specify file for log message. * A new program partclone.chkimg was added to help checking img by CRC. -- Steven Shiau Wed, 17 Jun 2009 10:34:00 +0800 partclone (0.1.1-11) unstable; urgency=low [Thomas Tsai] * update clear_buf * The patch from Kristian Erik Hermansen. fix progress.c:152- SECURITY: fprintf call should have "%s" as argument 1 -- Steven Shiau Sat, 13 Jun 2009 14:39:00 +0800 partclone (0.1.1-10) unstable; urgency=low [Thomas Tsai] * Bug fixed: pointer problem was fixed. * Bug fixed: buffer overflow problem was fixed. Thanks to Kristian Erik Hermansen and Piavlo. * Bug fixed: a bug about hfs+ was fixed. -- Steven Shiau Wed, 10 Jun 2009 10:39:00 +0800 partclone (0.1.1-9) unstable; urgency=low [Steven Shiau] * Some output messages were polished again. -- Steven Shiau Tue, 02 Jun 2009 18:09:00 +0800 partclone (0.1.1-8) unstable; urgency=low [Thomas Tsai] * Some output messages were polished. -- Steven Shiau Tue, 02 Jun 2009 16:51:00 +0800 partclone (0.1.1-7) unstable; urgency=low [Thomas Tsai] * Bug fixed: Progress update with nogui, "Calculating bitmap..." was added without option -d. -- Steven Shiau Mon, 01 Jun 2009 22:36:00 +0800 partclone (0.1.1-6) unstable; urgency=low [Thomas Tsai] * bug of CRC in 64 bit image problem was fixed. A better method will be imlemented in the nexe version of image format. -- Steven Shiau Sat, 30 May 2009 12:10:00 +0800 partclone (0.1.1-5) unstable; urgency=low [Thomas Tsai] * bug of time calculating was fixed. -- Steven Shiau Wed, 27 May 2009 22:13:00 +0800 partclone (0.1.1-4) unstable; urgency=low [Thomas Tsai] * Update default RES from 10000 to 1000. -- Steven Shiau Wed, 27 May 2009 12:59:00 +0800 partclone (0.1.1-3) unstable; urgency=low [Thomas Tsai] * Bug fixed: block device should not have to use "--overwrite". -- Steven Shiau Wed, 27 May 2009 11:23:00 +0800 partclone (0.1.1-2) unstable; urgency=low [Thomas Tsai] * partclone.ntfsreloc is linked to partclone.ntfsfixboot. -- Steven Shiau Fri, 22 May 2009 13:52:00 +0800 partclone (0.1.1-1) unstable; urgency=low [Thomas Tsai] * Minor updates for output messages. * New Feature: add argument to set fresh of progress bar * New Feature: restore to new file(non-block device) * A bug about crc check in 64bit image * Update partclone.ntfsreloc to ntfsfixboot.c from http://cc.jct.ac.il/~shaneh/ntfsfixboot.c -- root Fri, 22 May 2009 05:52:00 +0800 partclone (0.1.0-10) unstable; urgency=low [ Thomas Tsai ] * Bug fixed: clonezilla-Bugs-2784676. Thanks to njorl _at_ users sourceforge net. -- Steven Shiau Fri, 01 May 2009 10:55:00 +0800 partclone (0.1.0-9) unstable; urgency=low [ Steven Shiau ] * Minor updates for output messages. -- Steven Shiau Sun, 26 Apr 2009 13:54:00 +0800 partclone (0.1.0-8) unstable; urgency=low [ Steven Shiau ] * Minor updates for output messages. [ Thomas Tsai ] * EXECNAME was added for partclone.restore. -- Steven Shiau Fri, 24 Apr 2009 14:07:00 +0800 partclone (0.1.0-7) unstable; urgency=low [ Thomas Tsai ] * partclone.ext4dev is linkded now. -- Steven Shiau Thu, 23 Apr 2009 19:01:00 +0800 partclone (0.1.0-6) unstable; urgency=low [ Thomas Tsai ] * A bug about partclone.restore used to restore known file systems was fixed. -- Steven Shiau Thu, 18 Apr 2009 09:59:00 +0800 partclone (0.1.0-5) unstable; urgency=low [ Thomas Tsai ] * A bug about checking partition size was fixed. -- Steven Shiau Thu, 16 Apr 2009 15:03:00 +0800 partclone (0.1.0-4) unstable; urgency=low [ Thomas Tsai ] * Local device to device copy mode option "-b, --dd-mode" was changed to be "-b, --dev-to-dev" * A bug about partclone.dd wrongly get the partition size was fixed. -- Steven Shiau Thu, 16 Apr 2009 12:16:00 +0800 partclone (0.1.0-3) unstable; urgency=low [ Thomas Tsai ] * Bug fixed: partclone.ntfs statistics data was wrong when doing partition to partition clone. -- Steven Shiau Tue, 15 Apr 2009 10:52:00 +0800 partclone (0.1.0-2) unstable; urgency=low [ Steven Shiau ] * --enable-static is on again. -- Steven Shiau Tue, 10 Apr 2009 11:47:00 +0800 partclone (0.1.0-1) unstable; urgency=low [ Thomas Tsai ] * partclone.ext4, partclone.dd, partclone.restore were added. -- Steven Shiau Tue, 07 Apr 2009 15:01:00 +0800 partclone (0.0.9-4) unstable; urgency=low [ Thomas Tsai ] * A bug about FAT12 was fixed. -- Steven Shiau Tue, 30 Dec 2008 13:41:00 +0800 partclone (0.0.9-3) unstable; urgency=low [ Steven Shiau ] * New upstream ntfsreloc.c 0.8. -- Steven Shiau Thu, 25 Dec 2008 15:32:00 +0800 partclone (0.0.9-2) unstable; urgency=low [ Thomas Tsai ] * Update dirty message for ntfsclone-ng. * Check filesystem before cloning partition. Partclone will make sure that. * Add check hfs_plus filesystem before cloning volume. * Update fatclone.c fatclone.h clearly. update dirty message for extfs. -- Steven Shiau Mon, 22 Dec 2008 09:46:00 +0800 partclone (0.0.9-1) unstable; urgency=low # New features: partclone.ntfsreloc and partclone.ntfs were added. -- Steven Shiau Thu, 30 Oct 2008 10:51:00 +0800 partclone (0.0.8-8) unstable; urgency=low # Bug fixed: Failing to restore fat32 image was fixed by Thomas Tsai. -- Steven Shiau Wed, 30 Jul 2008 09:18:00 +0800 partclone (0.0.8-7) unstable; urgency=low # partclone.hfsplus link was added by Thomas Tsai. -- Steven Shiau Thu, 24 Jul 2008 11:53:00 +0800 partclone (0.0.8-6) unstable; urgency=low # Bug fixed: partclone.fat12 link was not done. -- Steven Shiau Fri, 11 Jul 2008 16:11:00 +0800 partclone (0.0.8-5) unstable; urgency=low # fat12 was added by Thomas Tsai. -- Steven Shiau Fri, 11 Jul 2008 15:03:00 +0800 partclone (0.0.8-4) unstable; urgency=low # Enable static linking. -- Steven Shiau Sat, 28 Jun 2008 10:22:00 +0800 partclone (0.0.8-3) unstable; urgency=low # Some minor updates about messages by Thomas Tsai. -- Steven Shiau Sun, 15 Jun 2008 22:48:00 +0800 partclone (0.0.8-2) unstable; urgency=low # configure.ac updated by Thomas Tsai. # partclone website is www.partclone.org now. -- Steven Shiau Mon, 26 May 2008 14:19:00 +0800 partclone (0.0.8-1) unstable; urgency=low # clone.$FS was renamed as partclone.$FS by Thomas Tsai. -- Steven Shiau Sun, 25 May 2008 09:19:00 +0800 partclone (0.0.7-4) unstable; urgency=low # Some bugs about ncursesw were fixed by Thomas Tsai. -- Steven Shiau Fri, 16 May 2008 16:18:00 +0800 partclone (0.0.7-3) unstable; urgency=low # Some bugs about ncursesw were fixed by Thomas Tsai. -- Steven Shiau Thu, 06 May 2008 23:00:00 +0800 partclone (0.0.7-2) unstable; urgency=low # Use --enable-ncursesw by default. -- Steven Shiau Thu, 01 May 2008 11:13:00 +0800 partclone (0.0.7-1) unstable; urgency=low # New functions: TUI mode for output done by Thomas Tsai. -- Steven Shiau Thu, 01 May 2008 11:08:00 +0800 partclone (0.0.6-4) unstable; urgency=low # Some new function for #14 "TUI of status reports" from Thomas Tsai. # Smaller FS_MAGIC_SIZE in main.c. -- Steven Shiau Tue, 22 Apr 2008 14:52:00 +0800 partclone (0.0.6-3) unstable; urgency=low # Bug fixed: version was not changed. -- Steven Shiau Thu, 21 Feb 2008 13:40:00 +0800 partclone (0.0.6-2) unstable; urgency=low # Bug fixed: clone.fat was not complied. -- Steven Shiau Wed, 20 Feb 2008 22:47:00 +0800 partclone (0.0.6-1) unstable; urgency=low # clone.fat was added by Thomas Tsai. -- Steven Shiau Wed, 20 Feb 2008 22:41:00 +0800 partclone (0.0.5-16) unstable; urgency=low # Typos fixed. # Bug fixed: partition to partition clone size checking failed. -- Steven Shiau Sat, 16 Feb 2008 10:02:00 +0800 partclone (0.0.5-15) unstable; urgency=low # partclone.nchc.org.tw was put without http:// in usage. -- Steven Shiau Mon, 04 Feb 2008 13:47:00 +0800 partclone (0.0.5-14) unstable; urgency=low # Some minor bugs fixed by Thomas Tsai. # http://partclone.nchc.org.tw was added in usage. -- Steven Shiau Mon, 04 Feb 2008 13:45:00 +0800 partclone (0.0.5-13) unstable; urgency=low * Bugs fixed and feature added by Thomas Tsai: # reduce seek time # fix number of Ave.Rate # check every filesystem's image_head data... # add new option to disable device and free space checking -- Steven Shiau Tue, 30 Jan 2008 23:07:00 +0800 partclone (0.0.5-12) unstable; urgency=low * Bug fixed by Thomas Tsai: Partition size checking failed in some cases. -- Steven Shiau Tue, 30 Jan 2008 21:08:00 +0800 partclone (0.0.5-11) unstable; urgency=low * Bug fixed by Thomas Tsai: Partition size checking failed -- Steven Shiau Tue, 29 Jan 2008 16:47:00 +0800 partclone (0.0.5-10) unstable; urgency=low * Functions to check memory size, check_free_space were added by Thomas Tsai. -- Steven Shiau Wed, 23 Jan 2008 22:57:00 +0800 partclone (0.0.5-9) unstable; urgency=low * Thomas Tsai added: New function rescue_sector. UNSTALBE feature, support device to device. Some other minor changes. -- Steven Shiau Sun, 20 Jan 2008 14:15:00 +0800 partclone (0.0.5-8) unstable; urgency=low * Some minor changes on ticket #18 from Thomas Tsai. -- Steven Shiau Fri, 11 Jan 2008 09:24:00 +0800 partclone (0.0.5-7) unstable; urgency=low * Some minor changes. -- Steven Shiau Wed, 9 Jan 2008 22:45:00 +0800 partclone (0.0.5-6) unstable; urgency=low * Thomas Tsai enhanced the status report. -- Steven Shiau Wed, 9 Jan 2008 09:15:00 +0800 partclone (0.0.5-5) unstable; urgency=low * Thomas Tsai closed ticket #18: Add a saving/restoring rate and estimated time to finish job in the status report. -- Steven Shiau Sun, 8 Jan 2008 15:12:00 +0800 partclone (0.0.5-4) unstable; urgency=low * Thomas Tsai closed these tickets: #12: Command without any option should show only short help messages. #13: Change "HFSPLUS" as "HFS+" or "HFS Plus". #15 (Sync after image is restored). #17: Show program name "partclone" and version number and url in the status report. -- Steven Shiau Sun, 7 Jan 2008 17:05:00 +0800 partclone (0.0.5-3) unstable; urgency=low * Static linking was disabled in debian/rules. -- Steven Shiau Sun, 6 Jan 2008 16:34:00 +0800 partclone (0.0.5-2) unstable; urgency=low * Description for deb package was updated. -- Steven Shiau Fri, 4 Jan 2008 21:40:00 +0800 partclone (0.0.5-1) unstable; urgency=low * [bugfix] reopen and close ticket #8 - fix debian packaging linking permission issue. -- Jazz Yao-Tsung Wang Fri, 4 Jan 2008 11:54:14 +0800 partclone (0.0.4-5) unstable; urgency=low * close ticket #8. Thomas added some alias programs when making install. -- Steven Shiau Fri, 4 Jan 2008 11:12:00 +0800 partclone (0.0.4-3ubuntu1) feisty; urgency=low * add support of static linking to configure.ac and src/Makefile.am * [BUGFIX #1] fixed static linking time error while enabling XFS file system support. * modified debian packaginf control and rules to fix some mistakes. -- Jazz Yao-Tsung Wang Wed, 2 Jan 2008 21:23:52 +0800 partclone (0.0.4-3) unstable; urgency=low * A Bug about restoring image from stdin was fixed by Jazz Wang. * zh_TW.po was updated. -- Steven Shiau Sun, 1 Jan 2008 20:20:00 +0800 partclone (0.0.4-2) unstable; urgency=low * Updated config by Jazz Wang so that static linking now it's better. Not finished. * Help messages updated. -- Steven Shiau Sun, 1 Jan 2008 11:20:00 +0800 partclone (0.0.4-1) unstable; urgency=low * Initial release. * modify rules -- Yu-Chin Tsai Thu, 13 Dec 2007 10:48:03 +0800 partclone-0.2.86/README.Packages/debian/compat000066400000000000000000000000021262102574200206710ustar00rootroot000000000000009 partclone-0.2.86/README.Packages/debian/control000066400000000000000000000024521262102574200211010ustar00rootroot00000000000000Source: partclone Section: admin Priority: extra Maintainer: Yu-Chin Tsai Build-Depends: debhelper (>= 9), dpkg-dev (>= 1.16.1~), dh-autoreconf, autotools-dev, pkg-config, xsltproc, docbook-xsl, docbook-xml, libncursesw5-dev, libtinfo-dev, e2fslibs-dev (>= 1.41.3), libbsd-dev, ntfs-3g-dev|libntfs-dev, xfslibs-dev, libreiserfs0.3-dev, libreiser4-dev, libufs2 (>= 7.2), libvmfs (>= 0.2.5), libjfs-dev, libblkid-dev, nilfs-tools Standards-Version: 3.9.3 Package: partclone Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} Description: Utility to clone and restore a partition. This project like the well-known backup utility "Partition Image" a.k.a partimage. . Partclone provides utilities to back up used blocks and design for higher compatibility of the file system using supported library like e2fslibs. . check the project website for more details http://partclone.org Package: partclone-dbg Section: debug Priority: extra Architecture: any Depends: ${misc:Depends}, partclone (= ${binary:Version}) Description: Utility to clone and restore a partition for debug. This project like the well-known backup utility "Partition Image" a.k.a partimage. . This package contains the debugging symbols. . check the project website for more details http://partclone.org partclone-0.2.86/README.Packages/debian/copyright000066400000000000000000000067701262102574200214400ustar00rootroot00000000000000Format: http://dep.debian.net/deps/dep5 Upstream-Name: partclone Upstream-Contact: Yu-Chin Tsai Source: https://github.com/Thomas-Tsai/partclone Files: * Copyright: 2006-2012 Thomas Tsai 2007-2012 Steven Shiau 2007-2008 Jazz Wang License: GPL-2+ see below for the text of this license. Files: debian/* Copyright: 2012 Thomas Tsai 2011 Georges Khaznadar License: GPL-2+ see below for the text of this license. Files: src/ufs/libufs.h Copyright: 2002 Juli Mallett License: FreeBSD-like see below for the text of this license. Files: src/ufs/sys/* Copyright: 1987, 1988, 1993 The Regents of the University of California. License: FreeBSD-like see below for the text of this license. Files: src/ufs/ffs/* Copyright: 1982, 1986, 1993 The Regents of the University of California. License: FreeBSD-like see below for the text of this license. Files: src/ufs/ufs/fs.h Copyright: 1982, 1986, 1993 The Regents of the University of California. License: FreeBSD-like see below for the text of this license. Files: src/ufs/ufs/dinode.h Copyright: 2002 Networks Associates Technology, Inc. License: FreeBSD-like see below for the text of this license. License: FreeBSD-like Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 4. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. . THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. License: GPL-2+ This package is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. . This package is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. . You should have received a copy of the GNU General Public License along with this program. If not, see . On Debian systems, the complete text of the GNU General Public License version 2 can be found in "/usr/share/common-licenses/GPL-2". partclone-0.2.86/README.Packages/debian/dirs000066400000000000000000000000111262102574200203470ustar00rootroot00000000000000usr/sbin partclone-0.2.86/README.Packages/debian/docs000066400000000000000000000000171262102574200203440ustar00rootroot00000000000000NEWS README.md partclone-0.2.86/README.Packages/debian/rules000077500000000000000000000024161262102574200205560ustar00rootroot00000000000000#!/usr/bin/make -f # -*- makefile -*- # Sample debian/rules that uses debhelper. # This file was originally written by Joey Hess and Craig Small. # As a special exception, when this file is copied by dh-make into a # dh-make output file, you may use that output file without restriction. # This special exception was added by Craig Small in version 0.37 of dh-make. # Uncomment this to turn on verbose mode. export DH_VERBOSE=1 DPKG_EXPORT_BUILDFLAGS = 1 include /usr/share/dpkg/buildflags.mk override_dh_auto_configure: # Add here commands to configure the package. #cp /usr/share/misc/config.sub . #cp /usr/share/misc/config.guess . #autoreconf #./configure --prefix=/usr --mandir=\$${prefix}/share/man --infodir=\$${prefix}/share/info LDFLAGS="-Wl,-z,defs" --enable-ncursesw --enable-extfs --enable-static dh_auto_configure -- --enable-ncursesw --enable-all override_dh_auto_install: $(MAKE) DESTDIR=$$(pwd)/debian/partclone prefix=/usr install override_dh_auto_clean: dh_auto_clean rm -f get_lib_version rm -f config.sub configure Makefile.in aclocal.m4 config.guess rm -f src/Makefile.in docs/Makefile.in override_dh_clean: dh_clean -X fail-mbr/fail-mbr.bin.orig override_dh_strip: dh_strip --dbg-package=partclone-dbg %: dh $@ --with autoreconf --with autotools-dev partclone-0.2.86/README.Packages/debian/source/000077500000000000000000000000001262102574200207735ustar00rootroot00000000000000partclone-0.2.86/README.Packages/debian/source/format000066400000000000000000000000141262102574200222010ustar00rootroot000000000000003.0 (quilt) partclone-0.2.86/README.Packages/partclone.spec000066400000000000000000000066151262102574200211240ustar00rootroot00000000000000Name: partclone Version: 0.1.0 Release: 10 Group: System/Filesystems URL: http://partclone.org License: GPL Summary: File System Clone Utilities for ext2/3/4, reiserfs, reiser4, xfs, hfs+ File System Source0: http://free.nchc.org.tw/drbl-core/pool/drbl/unstable/p/partclone/%{name}_%{version}-%{release}.tar.gz BuildRequires: e2fsprogs-devel >= 1.41.3, libprogsreiserfs-devel-static, reiser4progs, xfsprogs-devel, ntfsprogs-devel, ncurses-static BuildRoot: %{_tmppath}/%{name}-build %description A set of file system clone utilities, including ext2/3, reiserfs, reiser4, xfs, hfs+ file system Authors: -------- Thomas Tsai Jazz Wang http://partclone.org, http://partclone.nchc.org.tw %prep %setup -q -n %{name} %build [ -d $RPM_BUILD_ROOT ] && rm -rf $RPM_BUILD_ROOT ./configure --prefix=/usr --enable-all --enable-static --enable-ncursesw LIBS=-ltinfo make -j4 %install make DESTDIR=$RPM_BUILD_ROOT install %post %postun ldconfig %clean rm -rf $RPM_BUILD_ROOT %files %defattr(-,root,root) %doc AUTHORS COPYING ChangeLog NEWS README TODO %doc %{_mandir}/man?/* %{_sbindir}/* /usr/share/locale/* %changelog * Fri May 01 2009 - Steven Shiau 0.1.0-10 - New upstream 0.1.0-10. * Sun Apr 26 2009 - Steven Shiau 0.1.0-9 - New upstream 0.1.0-9. * Fri Apr 24 2009 - Steven Shiau 0.1.0-8 - New upstream 0.1.0-8. * Thu Apr 23 2009 - Steven Shiau 0.1.0-7 - New upstream 0.1.0-7. * Tue Apr 21 2009 - Steven Shiau 0.1.0-6 - New upstream 0.1.0-6. * Fri Apr 17 2009 - Steven Shiau 0.1.0-5 - New upstream 0.1.0-5. * Tue Apr 14 2009 - thomas _at_ nchc.org.tw 0.1.0-2 - update configure for FC10 * Sun Apr 12 2009 - Steven Shiau 0.1.0-2 - New upstream 0.1.0. * Tue Dec 30 2008 - Steven Shiau 0.0.9-4 - A bug about FAT12 was fixed by Thomas Tsai. * Wed Dec 25 2008 - Steven Shiau 0.0.9-3 - New upstream 0.0.9-3. * Mon Dec 22 2008 - Steven Shiau 0.0.9-2 - New upstream 0.0.9-2. * Sun Jun 16 2008 - Steven Shiau 0.0.8-3 - New upstream 0.0.8-3. * Mon May 26 2008 - Steven Shiau 0.0.8-2 - New upstream 0.0.8-2. * Sun May 25 2008 - Steven Shiau 0.0.8-1 - New upstream 0.0.8-1. * Thu Feb 21 2008 - Steven Shiau 0.0.6-3 - Bug fixed: clone.fat was not compiled. * Thu Feb 21 2008 - Steven Shiau 0.0.6-1 - New upstream 0.0.6-1. * Sat Feb 16 2008 - Steven Shiau 0.0.5-16 - New upstream 0.0.5-16. * Mon Feb 04 2008 - Steven Shiau 0.0.5-15 - New upstream 0.0.5-15. * Thu Jan 24 2008 - Steven Shiau 0.0.5-10 - New upstream 0.0.5-10. * Fri Jan 04 2008 - Steven Shiau 0.0.5-1 - New upstream 0.0.5-1. * Thu Jan 03 2008 - Steven Shiau 0.0.4-4 - Sync the version number with Debian package. - Enable static linking. * Mon Dec 31 2007 - Steven Shiau 0.0.1-2 - Some doc and debian rules were added by Thomas Tsai. * Mon Dec 10 2007 - Steven Shiau 0.0.1-1 - Initial release for partclone. partclone-0.2.86/README.md000066400000000000000000000025431262102574200150620ustar00rootroot00000000000000Partclone is a project similar to the well-known backup utility "Partition Image" a.k.a partimage. Partclone provides utilities to back up and restore used-blocks of a partition and it is designed for higher compatibility of the file system by using existing library, e.g. e2fslibs is used to read and write the ext2 partition. Partclone now supports ext2, ext3, ext4, hfs+, reiserfs, reiser4, btrfs, vmfs3, vmfs5, xfs, jfs, ufs, ntfs, fat(12/16/32), exfat... We made some utilies: * partclone.ext2, partclone.ext3, partclone.extfs * partclone.ext4 * partclone.reiserfs * partclone.reiser4 * partclone.xfs * partclone.exfat * partclone.fat (fat 12, fat 16, fat 32) * partclone.ntfs * partclone.hfsp * partclone.vmfs(v3 and v5) * partclone.ufs * partclone.jfs * partclone.btrfs * partclone.minix * partclone.f2fs * partclone.nilfs * partclone.info * partclone.restore * partclone.chkimg * partclone.dd ... Basic Usage: - clone partition to image `partclone.ext4 -d -c -s /dev/sda1 -o sda1.img` - restore image to partition `partclone.ext4 -d -r -s sda1.img -o /dev/sda1` - partiiton to partition clone `partclone.ext4 -d -b -s /dev/sda1 -o /dev/sdb1` - display image information `partclone.info -s sda1.img` - check image `partclone.chkimg -s sda1.img` For more info about partclone, check our website http://partclone.org or github-wiki. partclone-0.2.86/TODO000066400000000000000000000002031262102574200142620ustar00rootroot00000000000000* list file system library version * multi output device for restore * nilfs support * wbfs support * zfs support * more documents partclone-0.2.86/aclocal.m4000066400000000000000000001443471262102574200154540ustar00rootroot00000000000000# generated automatically by aclocal 1.15 -*- Autoconf -*- # Copyright (C) 1996-2014 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],, [m4_warning([this file was generated for autoconf 2.69. You have another version of autoconf. It may work, but is not guaranteed to. If you have problems, you may need to regenerate the build system entirely. To do so, use the procedure documented by the package, typically 'autoreconf'.])]) # pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- # serial 1 (pkg-config-0.24) # # Copyright © 2004 Scott James Remnant . # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # PKG_PROG_PKG_CONFIG([MIN-VERSION]) # ---------------------------------- AC_DEFUN([PKG_PROG_PKG_CONFIG], [m4_pattern_forbid([^_?PKG_[A-Z_]+$]) m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$]) m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$]) AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility]) AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path]) AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path]) if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) fi if test -n "$PKG_CONFIG"; then _pkg_min_version=m4_default([$1], [0.9.0]) AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) PKG_CONFIG="" fi fi[]dnl ])# PKG_PROG_PKG_CONFIG # PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) # # Check to see whether a particular set of modules exists. Similar # to PKG_CHECK_MODULES(), but does not set variables or print errors. # # Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG]) # only at the first occurence in configure.ac, so if the first place # it's called might be skipped (such as if it is within an "if", you # have to call PKG_CHECK_EXISTS manually # -------------------------------------------------------------- AC_DEFUN([PKG_CHECK_EXISTS], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl if test -n "$PKG_CONFIG" && \ AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then m4_default([$2], [:]) m4_ifvaln([$3], [else $3])dnl fi]) # _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) # --------------------------------------------- m4_define([_PKG_CONFIG], [if test -n "$$1"; then pkg_cv_[]$1="$$1" elif test -n "$PKG_CONFIG"; then PKG_CHECK_EXISTS([$3], [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes ], [pkg_failed=yes]) else pkg_failed=untried fi[]dnl ])# _PKG_CONFIG # _PKG_SHORT_ERRORS_SUPPORTED # ----------------------------- AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], [AC_REQUIRE([PKG_PROG_PKG_CONFIG]) if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi[]dnl ])# _PKG_SHORT_ERRORS_SUPPORTED # PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], # [ACTION-IF-NOT-FOUND]) # # # Note that if there is a possibility the first call to # PKG_CHECK_MODULES might not happen, you should be sure to include an # explicit call to PKG_PROG_PKG_CONFIG in your configure.ac # # # -------------------------------------------------------------- AC_DEFUN([PKG_CHECK_MODULES], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl pkg_failed=no AC_MSG_CHECKING([for $1]) _PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) _PKG_CONFIG([$1][_LIBS], [libs], [$2]) m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS and $1[]_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details.]) if test $pkg_failed = yes; then AC_MSG_RESULT([no]) _PKG_SHORT_ERRORS_SUPPORTED if test $_pkg_short_errors_supported = yes; then $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1` else $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD m4_default([$4], [AC_MSG_ERROR( [Package requirements ($2) were not met: $$1_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. _PKG_TEXT])[]dnl ]) elif test $pkg_failed = untried; then AC_MSG_RESULT([no]) m4_default([$4], [AC_MSG_FAILURE( [The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. _PKG_TEXT To get pkg-config, see .])[]dnl ]) else $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS $1[]_LIBS=$pkg_cv_[]$1[]_LIBS AC_MSG_RESULT([yes]) $3 fi[]dnl ])# PKG_CHECK_MODULES # PKG_INSTALLDIR(DIRECTORY) # ------------------------- # Substitutes the variable pkgconfigdir as the location where a module # should install pkg-config .pc files. By default the directory is # $libdir/pkgconfig, but the default can be changed by passing # DIRECTORY. The user can override through the --with-pkgconfigdir # parameter. AC_DEFUN([PKG_INSTALLDIR], [m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])]) m4_pushdef([pkg_description], [pkg-config installation directory @<:@]pkg_default[@:>@]) AC_ARG_WITH([pkgconfigdir], [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],, [with_pkgconfigdir=]pkg_default) AC_SUBST([pkgconfigdir], [$with_pkgconfigdir]) m4_popdef([pkg_default]) m4_popdef([pkg_description]) ]) dnl PKG_INSTALLDIR # PKG_NOARCH_INSTALLDIR(DIRECTORY) # ------------------------- # Substitutes the variable noarch_pkgconfigdir as the location where a # module should install arch-independent pkg-config .pc files. By # default the directory is $datadir/pkgconfig, but the default can be # changed by passing DIRECTORY. The user can override through the # --with-noarch-pkgconfigdir parameter. AC_DEFUN([PKG_NOARCH_INSTALLDIR], [m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])]) m4_pushdef([pkg_description], [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@]) AC_ARG_WITH([noarch-pkgconfigdir], [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],, [with_noarch_pkgconfigdir=]pkg_default) AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir]) m4_popdef([pkg_default]) m4_popdef([pkg_description]) ]) dnl PKG_NOARCH_INSTALLDIR # PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE, # [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) # ------------------------------------------- # Retrieves the value of the pkg-config variable for the given module. AC_DEFUN([PKG_CHECK_VAR], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl _PKG_CONFIG([$1], [variable="][$3]["], [$2]) AS_VAR_COPY([$1], [pkg_cv_][$1]) AS_VAR_IF([$1], [""], [$5], [$4])dnl ])# PKG_CHECK_VAR # Copyright (C) 2002-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_AUTOMAKE_VERSION(VERSION) # ---------------------------- # Automake X.Y traces this macro to ensure aclocal.m4 has been # generated from the m4 files accompanying Automake X.Y. # (This private macro should not be called outside this file.) AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version='1.15' dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to dnl require some minimum version. Point them to the right macro. m4_if([$1], [1.15], [], [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl ]) # _AM_AUTOCONF_VERSION(VERSION) # ----------------------------- # aclocal traces this macro to find the Autoconf version. # This is a private macro too. Using m4_define simplifies # the logic in aclocal, which can simply ignore this definition. m4_define([_AM_AUTOCONF_VERSION], []) # AM_SET_CURRENT_AUTOMAKE_VERSION # ------------------------------- # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. # This function is AC_REQUIREd by AM_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], [AM_AUTOMAKE_VERSION([1.15])dnl m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) # AM_AUX_DIR_EXPAND -*- Autoconf -*- # Copyright (C) 2001-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets # $ac_aux_dir to '$srcdir/foo'. In other projects, it is set to # '$srcdir', '$srcdir/..', or '$srcdir/../..'. # # Of course, Automake must honor this variable whenever it calls a # tool from the auxiliary directory. The problem is that $srcdir (and # therefore $ac_aux_dir as well) can be either absolute or relative, # depending on how configure is run. This is pretty annoying, since # it makes $ac_aux_dir quite unusable in subdirectories: in the top # source directory, any form will work fine, but in subdirectories a # relative path needs to be adjusted first. # # $ac_aux_dir/missing # fails when called from a subdirectory if $ac_aux_dir is relative # $top_srcdir/$ac_aux_dir/missing # fails if $ac_aux_dir is absolute, # fails when called from a subdirectory in a VPATH build with # a relative $ac_aux_dir # # The reason of the latter failure is that $top_srcdir and $ac_aux_dir # are both prefixed by $srcdir. In an in-source build this is usually # harmless because $srcdir is '.', but things will broke when you # start a VPATH build or use an absolute $srcdir. # # So we could use something similar to $top_srcdir/$ac_aux_dir/missing, # iff we strip the leading $srcdir from $ac_aux_dir. That would be: # am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` # and then we would define $MISSING as # MISSING="\${SHELL} $am_aux_dir/missing" # This will work as long as MISSING is not called from configure, because # unfortunately $(top_srcdir) has no meaning in configure. # However there are other variables, like CC, which are often used in # configure, and could therefore not use this "fixed" $ac_aux_dir. # # Another solution, used here, is to always expand $ac_aux_dir to an # absolute PATH. The drawback is that using absolute paths prevent a # configured tree to be moved without reconfiguration. AC_DEFUN([AM_AUX_DIR_EXPAND], [AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl # Expand $ac_aux_dir to an absolute path. am_aux_dir=`cd "$ac_aux_dir" && pwd` ]) # AM_CONDITIONAL -*- Autoconf -*- # Copyright (C) 1997-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_CONDITIONAL(NAME, SHELL-CONDITION) # ------------------------------------- # Define a conditional. AC_DEFUN([AM_CONDITIONAL], [AC_PREREQ([2.52])dnl m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl AC_SUBST([$1_TRUE])dnl AC_SUBST([$1_FALSE])dnl _AM_SUBST_NOTMAKE([$1_TRUE])dnl _AM_SUBST_NOTMAKE([$1_FALSE])dnl m4_define([_AM_COND_VALUE_$1], [$2])dnl if $2; then $1_TRUE= $1_FALSE='#' else $1_TRUE='#' $1_FALSE= fi AC_CONFIG_COMMANDS_PRE( [if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then AC_MSG_ERROR([[conditional "$1" was never defined. Usually this means the macro was only invoked conditionally.]]) fi])]) # Copyright (C) 1999-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # There are a few dirty hacks below to avoid letting 'AC_PROG_CC' be # written in clear, in which case automake, when reading aclocal.m4, # will think it sees a *use*, and therefore will trigger all it's # C support machinery. Also note that it means that autoscan, seeing # CC etc. in the Makefile, will ask for an AC_PROG_CC use... # _AM_DEPENDENCIES(NAME) # ---------------------- # See how the compiler implements dependency checking. # NAME is "CC", "CXX", "OBJC", "OBJCXX", "UPC", or "GJC". # We try a few techniques and use that to set a single cache variable. # # We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was # modified to invoke _AM_DEPENDENCIES(CC); we would have a circular # dependency, and given that the user is not expected to run this macro, # just rely on AC_PROG_CC. AC_DEFUN([_AM_DEPENDENCIES], [AC_REQUIRE([AM_SET_DEPDIR])dnl AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl AC_REQUIRE([AM_MAKE_INCLUDE])dnl AC_REQUIRE([AM_DEP_TRACK])dnl m4_if([$1], [CC], [depcc="$CC" am_compiler_list=], [$1], [CXX], [depcc="$CXX" am_compiler_list=], [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'], [$1], [OBJCXX], [depcc="$OBJCXX" am_compiler_list='gcc3 gcc'], [$1], [UPC], [depcc="$UPC" am_compiler_list=], [$1], [GCJ], [depcc="$GCJ" am_compiler_list='gcc3 gcc'], [depcc="$$1" am_compiler_list=]) AC_CACHE_CHECK([dependency style of $depcc], [am_cv_$1_dependencies_compiler_type], [if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named 'D' -- because '-MD' means "put the output # in D". rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_$1_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` fi am__universal=false m4_case([$1], [CC], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac], [CXX], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac]) for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with '-c' and '-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle '-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # After this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested. if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_$1_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_$1_dependencies_compiler_type=none fi ]) AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) AM_CONDITIONAL([am__fastdep$1], [ test "x$enable_dependency_tracking" != xno \ && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) ]) # AM_SET_DEPDIR # ------------- # Choose a directory name for dependency files. # This macro is AC_REQUIREd in _AM_DEPENDENCIES. AC_DEFUN([AM_SET_DEPDIR], [AC_REQUIRE([AM_SET_LEADING_DOT])dnl AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl ]) # AM_DEP_TRACK # ------------ AC_DEFUN([AM_DEP_TRACK], [AC_ARG_ENABLE([dependency-tracking], [dnl AS_HELP_STRING( [--enable-dependency-tracking], [do not reject slow dependency extractors]) AS_HELP_STRING( [--disable-dependency-tracking], [speeds up one-time build])]) if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' am__nodep='_no' fi AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) AC_SUBST([AMDEPBACKSLASH])dnl _AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl AC_SUBST([am__nodep])dnl _AM_SUBST_NOTMAKE([am__nodep])dnl ]) # Generate code to set up dependency tracking. -*- Autoconf -*- # Copyright (C) 1999-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_OUTPUT_DEPENDENCY_COMMANDS # ------------------------------ AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], [{ # Older Autoconf quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. case $CONFIG_FILES in *\'*) eval set x "$CONFIG_FILES" ;; *) set x $CONFIG_FILES ;; esac shift for mf do # Strip MF so we end up with the name of the file. mf=`echo "$mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile or not. # We used to match only the files named 'Makefile.in', but # some people rename them; so instead we look at the file content. # Grep'ing the first line is not enough: some people post-process # each Makefile.in and add a new line on top of each file to say so. # Grep'ing the whole file is not good either: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then dirpart=`AS_DIRNAME("$mf")` else continue fi # Extract the definition of DEPDIR, am__include, and am__quote # from the Makefile without running 'make'. DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` test -z "$DEPDIR" && continue am__include=`sed -n 's/^am__include = //p' < "$mf"` test -z "$am__include" && continue am__quote=`sed -n 's/^am__quote = //p' < "$mf"` # Find all dependency output files, they are included files with # $(DEPDIR) in their names. We invoke sed twice because it is the # simplest approach to changing $(DEPDIR) to its actual value in the # expansion. for file in `sed -n " s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do # Make sure the directory exists. test -f "$dirpart/$file" && continue fdir=`AS_DIRNAME(["$file"])` AS_MKDIR_P([$dirpart/$fdir]) # echo "creating $dirpart/$file" echo '# dummy' > "$dirpart/$file" done done } ])# _AM_OUTPUT_DEPENDENCY_COMMANDS # AM_OUTPUT_DEPENDENCY_COMMANDS # ----------------------------- # This macro should only be invoked once -- use via AC_REQUIRE. # # This code is only required when automatic dependency tracking # is enabled. FIXME. This creates each '.P' file that we will # need in order to bootstrap the dependency handling code. AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], [AC_CONFIG_COMMANDS([depfiles], [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) ]) # Do all the work for Automake. -*- Autoconf -*- # Copyright (C) 1996-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This macro actually does too much. Some checks are only needed if # your package does certain things. But this isn't really a big deal. dnl Redefine AC_PROG_CC to automatically invoke _AM_PROG_CC_C_O. m4_define([AC_PROG_CC], m4_defn([AC_PROG_CC]) [_AM_PROG_CC_C_O ]) # AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) # AM_INIT_AUTOMAKE([OPTIONS]) # ----------------------------------------------- # The call with PACKAGE and VERSION arguments is the old style # call (pre autoconf-2.50), which is being phased out. PACKAGE # and VERSION should now be passed to AC_INIT and removed from # the call to AM_INIT_AUTOMAKE. # We support both call styles for the transition. After # the next Automake release, Autoconf can make the AC_INIT # arguments mandatory, and then we can depend on a new Autoconf # release and drop the old call support. AC_DEFUN([AM_INIT_AUTOMAKE], [AC_PREREQ([2.65])dnl dnl Autoconf wants to disallow AM_ names. We explicitly allow dnl the ones we care about. m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl AC_REQUIRE([AC_PROG_INSTALL])dnl if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl # test to see if srcdir already configured if test -f $srcdir/config.status; then AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi AC_SUBST([CYGPATH_W]) # Define the identity of the package. dnl Distinguish between old-style and new-style calls. m4_ifval([$2], [AC_DIAGNOSE([obsolete], [$0: two- and three-arguments forms are deprecated.]) m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl AC_SUBST([PACKAGE], [$1])dnl AC_SUBST([VERSION], [$2])], [_AM_SET_OPTIONS([$1])dnl dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. m4_if( m4_ifdef([AC_PACKAGE_NAME], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]), [ok:ok],, [m4_fatal([AC_INIT should be called with package and version arguments])])dnl AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl _AM_IF_OPTION([no-define],, [AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package]) AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl # Some tools Automake needs. AC_REQUIRE([AM_SANITY_CHECK])dnl AC_REQUIRE([AC_ARG_PROGRAM])dnl AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}]) AM_MISSING_PROG([AUTOCONF], [autoconf]) AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}]) AM_MISSING_PROG([AUTOHEADER], [autoheader]) AM_MISSING_PROG([MAKEINFO], [makeinfo]) AC_REQUIRE([AM_PROG_INSTALL_SH])dnl AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl AC_REQUIRE([AC_PROG_MKDIR_P])dnl # For better backward compatibility. To be removed once Automake 1.9.x # dies out for good. For more background, see: # # AC_SUBST([mkdir_p], ['$(MKDIR_P)']) # We need awk for the "check" target (and possibly the TAP driver). The # system "awk" is bad on some platforms. AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([AC_PROG_MAKE_SET])dnl AC_REQUIRE([AM_SET_LEADING_DOT])dnl _AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], [_AM_PROG_TAR([v7])])]) _AM_IF_OPTION([no-dependencies],, [AC_PROVIDE_IFELSE([AC_PROG_CC], [_AM_DEPENDENCIES([CC])], [m4_define([AC_PROG_CC], m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl AC_PROVIDE_IFELSE([AC_PROG_CXX], [_AM_DEPENDENCIES([CXX])], [m4_define([AC_PROG_CXX], m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJC], [_AM_DEPENDENCIES([OBJC])], [m4_define([AC_PROG_OBJC], m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJCXX], [_AM_DEPENDENCIES([OBJCXX])], [m4_define([AC_PROG_OBJCXX], m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl ]) AC_REQUIRE([AM_SILENT_RULES])dnl dnl The testsuite driver may need to know about EXEEXT, so add the dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below. AC_CONFIG_COMMANDS_PRE(dnl [m4_provide_if([_AM_COMPILER_EXEEXT], [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl # POSIX will say in a future version that running "rm -f" with no argument # is OK; and we want to be able to make that assumption in our Makefile # recipes. So use an aggressive probe to check that the usage we want is # actually supported "in the wild" to an acceptable degree. # See automake bug#10828. # To make any issue more visible, cause the running configure to be aborted # by default if the 'rm' program in use doesn't match our expectations; the # user can still override this though. if rm -f && rm -fr && rm -rf; then : OK; else cat >&2 <<'END' Oops! Your 'rm' program seems unable to run without file operands specified on the command line, even when the '-f' option is present. This is contrary to the behaviour of most rm programs out there, and not conforming with the upcoming POSIX standard: Please tell bug-automake@gnu.org about your system, including the value of your $PATH and any error possibly output before this message. This can help us improve future automake versions. END if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then echo 'Configuration will proceed anyway, since you have set the' >&2 echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 echo >&2 else cat >&2 <<'END' Aborting the configuration process, to ensure you take notice of the issue. You can download and install GNU coreutils to get an 'rm' implementation that behaves properly: . If you want to complete the configuration process using your problematic 'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM to "yes", and re-run configure. END AC_MSG_ERROR([Your 'rm' program is bad, sorry.]) fi fi dnl The trailing newline in this macro's definition is deliberate, for dnl backward compatibility and to allow trailing 'dnl'-style comments dnl after the AM_INIT_AUTOMAKE invocation. See automake bug#16841. ]) dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion. Do not dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further dnl mangled by Autoconf and run in a shell conditional statement. m4_define([_AC_COMPILER_EXEEXT], m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) # When config.status generates a header, we must update the stamp-h file. # This file resides in the same directory as the config header # that is generated. The stamp files are numbered to have different names. # Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the # loop where config.status creates the headers, so we can generate # our stamp files there. AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], [# Compute $1's index in $config_headers. _am_arg=$1 _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $_am_arg | $_am_arg:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) # Copyright (C) 2001-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_INSTALL_SH # ------------------ # Define $install_sh. AC_DEFUN([AM_PROG_INSTALL_SH], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl if test x"${install_sh+set}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi AC_SUBST([install_sh])]) # Copyright (C) 2003-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # Check whether the underlying file-system supports filenames # with a leading dot. For instance MS-DOS doesn't. AC_DEFUN([AM_SET_LEADING_DOT], [rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null AC_SUBST([am__leading_dot])]) # Check to see how 'make' treats includes. -*- Autoconf -*- # Copyright (C) 2001-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_MAKE_INCLUDE() # ----------------- # Check to see how make treats includes. AC_DEFUN([AM_MAKE_INCLUDE], [am_make=${MAKE-make} cat > confinc << 'END' am__doit: @echo this is the am__doit target .PHONY: am__doit END # If we don't find an include directive, just comment out the code. AC_MSG_CHECKING([for style of include used by $am_make]) am__include="#" am__quote= _am_result=none # First try GNU make style include. echo "include confinc" > confmf # Ignore all kinds of additional output from 'make'. case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=include am__quote= _am_result=GNU ;; esac # Now try BSD make style include. if test "$am__include" = "#"; then echo '.include "confinc"' > confmf case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=.include am__quote="\"" _am_result=BSD ;; esac fi AC_SUBST([am__include]) AC_SUBST([am__quote]) AC_MSG_RESULT([$_am_result]) rm -f confinc confmf ]) # Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- # Copyright (C) 1997-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_MISSING_PROG(NAME, PROGRAM) # ------------------------------ AC_DEFUN([AM_MISSING_PROG], [AC_REQUIRE([AM_MISSING_HAS_RUN]) $1=${$1-"${am_missing_run}$2"} AC_SUBST($1)]) # AM_MISSING_HAS_RUN # ------------------ # Define MISSING if not defined so far and test if it is modern enough. # If it is, set am_missing_run to use it, otherwise, to nothing. AC_DEFUN([AM_MISSING_HAS_RUN], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([missing])dnl if test x"${MISSING+set}" != xset; then case $am_aux_dir in *\ * | *\ *) MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; *) MISSING="\${SHELL} $am_aux_dir/missing" ;; esac fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then am_missing_run="$MISSING " else am_missing_run= AC_MSG_WARN(['missing' script is too old or missing]) fi ]) # Copyright (C) 2003-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_MKDIR_P # --------------- # Check for 'mkdir -p'. AC_DEFUN([AM_PROG_MKDIR_P], [AC_PREREQ([2.60])dnl AC_REQUIRE([AC_PROG_MKDIR_P])dnl dnl FIXME we are no longer going to remove this! adjust warning dnl FIXME message accordingly. AC_DIAGNOSE([obsolete], [$0: this macro is deprecated, and will soon be removed. You should use the Autoconf-provided 'AC][_PROG_MKDIR_P' macro instead, and use '$(MKDIR_P)' instead of '$(mkdir_p)'in your Makefile.am files.]) dnl Automake 1.8 to 1.9.6 used to define mkdir_p. We now use MKDIR_P, dnl while keeping a definition of mkdir_p for backward compatibility. dnl @MKDIR_P@ is magic: AC_OUTPUT adjusts its value for each Makefile. dnl However we cannot define mkdir_p as $(MKDIR_P) for the sake of dnl Makefile.ins that do not define MKDIR_P, so we do our own dnl adjustment using top_builddir (which is defined more often than dnl MKDIR_P). AC_SUBST([mkdir_p], ["$MKDIR_P"])dnl case $mkdir_p in [[\\/$]]* | ?:[[\\/]]*) ;; */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; esac ]) # Helper functions for option handling. -*- Autoconf -*- # Copyright (C) 2001-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_MANGLE_OPTION(NAME) # ----------------------- AC_DEFUN([_AM_MANGLE_OPTION], [[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) # _AM_SET_OPTION(NAME) # -------------------- # Set option NAME. Presently that only means defining a flag for this option. AC_DEFUN([_AM_SET_OPTION], [m4_define(_AM_MANGLE_OPTION([$1]), [1])]) # _AM_SET_OPTIONS(OPTIONS) # ------------------------ # OPTIONS is a space-separated list of Automake options. AC_DEFUN([_AM_SET_OPTIONS], [m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) # _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) # ------------------------------------------- # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. AC_DEFUN([_AM_IF_OPTION], [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) # Copyright (C) 1999-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_PROG_CC_C_O # --------------- # Like AC_PROG_CC_C_O, but changed for automake. We rewrite AC_PROG_CC # to automatically call this. AC_DEFUN([_AM_PROG_CC_C_O], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([compile])dnl AC_LANG_PUSH([C])dnl AC_CACHE_CHECK( [whether $CC understands -c and -o together], [am_cv_prog_cc_c_o], [AC_LANG_CONFTEST([AC_LANG_PROGRAM([])]) # Make sure it works both with $CC and with simple cc. # Following AC_PROG_CC_C_O, we do the test twice because some # compilers refuse to overwrite an existing .o file with -o, # though they will create one. am_cv_prog_cc_c_o=yes for am_i in 1 2; do if AM_RUN_LOG([$CC -c conftest.$ac_ext -o conftest2.$ac_objext]) \ && test -f conftest2.$ac_objext; then : OK else am_cv_prog_cc_c_o=no break fi done rm -f core conftest* unset am_i]) if test "$am_cv_prog_cc_c_o" != yes; then # Losing compiler, so override with the script. # FIXME: It is wrong to rewrite CC. # But if we don't then we get into trouble of one sort or another. # A longer-term fix would be to have automake use am__CC in this case, # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" CC="$am_aux_dir/compile $CC" fi AC_LANG_POP([C])]) # For backward compatibility. AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])]) # Copyright (C) 2001-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_RUN_LOG(COMMAND) # ------------------- # Run COMMAND, save the exit status in ac_status, and log it. # (This has been adapted from Autoconf's _AC_RUN_LOG macro.) AC_DEFUN([AM_RUN_LOG], [{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD (exit $ac_status); }]) # Check to make sure that the build environment is sane. -*- Autoconf -*- # Copyright (C) 1996-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_SANITY_CHECK # --------------- AC_DEFUN([AM_SANITY_CHECK], [AC_MSG_CHECKING([whether build environment is sane]) # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[[\\\"\#\$\&\'\`$am_lf]]*) AC_MSG_ERROR([unsafe absolute working directory name]);; esac case $srcdir in *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);; esac # Do 'set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( am_has_slept=no for am_try in 1 2; do echo "timestamp, slept: $am_has_slept" > conftest.file set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$[*]" = "X"; then # -L didn't work. set X `ls -t "$srcdir/configure" conftest.file` fi if test "$[*]" != "X $srcdir/configure conftest.file" \ && test "$[*]" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken alias in your environment]) fi if test "$[2]" = conftest.file || test $am_try -eq 2; then break fi # Just in case. sleep 1 am_has_slept=yes done test "$[2]" = conftest.file ) then # Ok. : else AC_MSG_ERROR([newly created file is older than distributed files! Check your system clock]) fi AC_MSG_RESULT([yes]) # If we didn't sleep, we still need to ensure time stamps of config.status and # generated files are strictly newer. am_sleep_pid= if grep 'slept: no' conftest.file >/dev/null 2>&1; then ( sleep 1 ) & am_sleep_pid=$! fi AC_CONFIG_COMMANDS_PRE( [AC_MSG_CHECKING([that generated files are newer than configure]) if test -n "$am_sleep_pid"; then # Hide warnings about reused PIDs. wait $am_sleep_pid 2>/dev/null fi AC_MSG_RESULT([done])]) rm -f conftest.file ]) # Copyright (C) 2009-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_SILENT_RULES([DEFAULT]) # -------------------------- # Enable less verbose build rules; with the default set to DEFAULT # ("yes" being less verbose, "no" or empty being verbose). AC_DEFUN([AM_SILENT_RULES], [AC_ARG_ENABLE([silent-rules], [dnl AS_HELP_STRING( [--enable-silent-rules], [less verbose build output (undo: "make V=1")]) AS_HELP_STRING( [--disable-silent-rules], [verbose build output (undo: "make V=0")])dnl ]) case $enable_silent_rules in @%:@ ((( yes) AM_DEFAULT_VERBOSITY=0;; no) AM_DEFAULT_VERBOSITY=1;; *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);; esac dnl dnl A few 'make' implementations (e.g., NonStop OS and NextStep) dnl do not support nested variable expansions. dnl See automake bug#9928 and bug#10237. am_make=${MAKE-make} AC_CACHE_CHECK([whether $am_make supports nested variables], [am_cv_make_support_nested_variables], [if AS_ECHO([['TRUE=$(BAR$(V)) BAR0=false BAR1=true V=1 am__doit: @$(TRUE) .PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then am_cv_make_support_nested_variables=yes else am_cv_make_support_nested_variables=no fi]) if test $am_cv_make_support_nested_variables = yes; then dnl Using '$V' instead of '$(V)' breaks IRIX make. AM_V='$(V)' AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' else AM_V=$AM_DEFAULT_VERBOSITY AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY fi AC_SUBST([AM_V])dnl AM_SUBST_NOTMAKE([AM_V])dnl AC_SUBST([AM_DEFAULT_V])dnl AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl AC_SUBST([AM_DEFAULT_VERBOSITY])dnl AM_BACKSLASH='\' AC_SUBST([AM_BACKSLASH])dnl _AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl ]) # Copyright (C) 2001-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_INSTALL_STRIP # --------------------- # One issue with vendor 'install' (even GNU) is that you can't # specify the program used to strip binaries. This is especially # annoying in cross-compiling environments, where the build's strip # is unlikely to handle the host's binaries. # Fortunately install-sh will honor a STRIPPROG variable, so we # always use install-sh in "make install-strip", and initialize # STRIPPROG with the value of the STRIP variable (set by the user). AC_DEFUN([AM_PROG_INSTALL_STRIP], [AC_REQUIRE([AM_PROG_INSTALL_SH])dnl # Installed binaries are usually stripped using 'strip' when the user # run "make install-strip". However 'strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the 'STRIP' environment variable to overrule this program. dnl Don't test for $cross_compiling = yes, because it might be 'maybe'. if test "$cross_compiling" != no; then AC_CHECK_TOOL([STRIP], [strip], :) fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" AC_SUBST([INSTALL_STRIP_PROGRAM])]) # Copyright (C) 2006-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_SUBST_NOTMAKE(VARIABLE) # --------------------------- # Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. # This macro is traced by Automake. AC_DEFUN([_AM_SUBST_NOTMAKE]) # AM_SUBST_NOTMAKE(VARIABLE) # -------------------------- # Public sister of _AM_SUBST_NOTMAKE. AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) # Check how to create a tarball. -*- Autoconf -*- # Copyright (C) 2004-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_PROG_TAR(FORMAT) # -------------------- # Check how to create a tarball in format FORMAT. # FORMAT should be one of 'v7', 'ustar', or 'pax'. # # Substitute a variable $(am__tar) that is a command # writing to stdout a FORMAT-tarball containing the directory # $tardir. # tardir=directory && $(am__tar) > result.tar # # Substitute a variable $(am__untar) that extract such # a tarball read from stdin. # $(am__untar) < result.tar # AC_DEFUN([_AM_PROG_TAR], [# Always define AMTAR for backward compatibility. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AC_SUBST([AMTAR], ['$${TAR-tar}']) # We'll loop over all known methods to create a tar archive until one works. _am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' m4_if([$1], [v7], [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'], [m4_case([$1], [ustar], [# The POSIX 1988 'ustar' format is defined with fixed-size fields. # There is notably a 21 bits limit for the UID and the GID. In fact, # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343 # and bug#13588). am_max_uid=2097151 # 2^21 - 1 am_max_gid=$am_max_uid # The $UID and $GID variables are not portable, so we need to resort # to the POSIX-mandated id(1) utility. Errors in the 'id' calls # below are definitely unexpected, so allow the users to see them # (that is, avoid stderr redirection). am_uid=`id -u || echo unknown` am_gid=`id -g || echo unknown` AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format]) if test $am_uid -le $am_max_uid; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) _am_tools=none fi AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format]) if test $am_gid -le $am_max_gid; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) _am_tools=none fi], [pax], [], [m4_fatal([Unknown tar format])]) AC_MSG_CHECKING([how to create a $1 tar archive]) # Go ahead even if we have the value already cached. We do so because we # need to set the values for the 'am__tar' and 'am__untar' variables. _am_tools=${am_cv_prog_tar_$1-$_am_tools} for _am_tool in $_am_tools; do case $_am_tool in gnutar) for _am_tar in tar gnutar gtar; do AM_RUN_LOG([$_am_tar --version]) && break done am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' am__untar="$_am_tar -xf -" ;; plaintar) # Must skip GNU tar: if it does not support --format= it doesn't create # ustar tarball either. (tar --version) >/dev/null 2>&1 && continue am__tar='tar chf - "$$tardir"' am__tar_='tar chf - "$tardir"' am__untar='tar xf -' ;; pax) am__tar='pax -L -x $1 -w "$$tardir"' am__tar_='pax -L -x $1 -w "$tardir"' am__untar='pax -r' ;; cpio) am__tar='find "$$tardir" -print | cpio -o -H $1 -L' am__tar_='find "$tardir" -print | cpio -o -H $1 -L' am__untar='cpio -i -H $1 -d' ;; none) am__tar=false am__tar_=false am__untar=false ;; esac # If the value was cached, stop now. We just wanted to have am__tar # and am__untar set. test -n "${am_cv_prog_tar_$1}" && break # tar/untar a dummy directory, and stop if the command works. rm -rf conftest.dir mkdir conftest.dir echo GrepMe > conftest.dir/file AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) rm -rf conftest.dir if test -s conftest.tar; then AM_RUN_LOG([$am__untar /dev/null 2>&1 && break fi done rm -rf conftest.dir AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) AC_MSG_RESULT([$am_cv_prog_tar_$1])]) AC_SUBST([am__tar]) AC_SUBST([am__untar]) ]) # _AM_PROG_TAR m4_include([m4/gettext.m4]) m4_include([m4/iconv.m4]) m4_include([m4/lib-ld.m4]) m4_include([m4/lib-link.m4]) m4_include([m4/lib-prefix.m4]) m4_include([m4/nls.m4]) m4_include([m4/po.m4]) m4_include([m4/progtest.m4]) partclone-0.2.86/compile000077500000000000000000000162451262102574200151650ustar00rootroot00000000000000#! /bin/sh # Wrapper for compilers which do not understand '-c -o'. scriptversion=2012-10-14.11; # UTC # Copyright (C) 1999-2014 Free Software Foundation, Inc. # Written by Tom Tromey . # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # This file is maintained in Automake, please report # bugs to or send patches to # . nl=' ' # We need space, tab and new line, in precisely that order. Quoting is # there to prevent tools from complaining about whitespace usage. IFS=" "" $nl" file_conv= # func_file_conv build_file lazy # Convert a $build file to $host form and store it in $file # Currently only supports Windows hosts. If the determined conversion # type is listed in (the comma separated) LAZY, no conversion will # take place. func_file_conv () { file=$1 case $file in / | /[!/]*) # absolute file, and not a UNC file if test -z "$file_conv"; then # lazily determine how to convert abs files case `uname -s` in MINGW*) file_conv=mingw ;; CYGWIN*) file_conv=cygwin ;; *) file_conv=wine ;; esac fi case $file_conv/,$2, in *,$file_conv,*) ;; mingw/*) file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` ;; cygwin/*) file=`cygpath -m "$file" || echo "$file"` ;; wine/*) file=`winepath -w "$file" || echo "$file"` ;; esac ;; esac } # func_cl_dashL linkdir # Make cl look for libraries in LINKDIR func_cl_dashL () { func_file_conv "$1" if test -z "$lib_path"; then lib_path=$file else lib_path="$lib_path;$file" fi linker_opts="$linker_opts -LIBPATH:$file" } # func_cl_dashl library # Do a library search-path lookup for cl func_cl_dashl () { lib=$1 found=no save_IFS=$IFS IFS=';' for dir in $lib_path $LIB do IFS=$save_IFS if $shared && test -f "$dir/$lib.dll.lib"; then found=yes lib=$dir/$lib.dll.lib break fi if test -f "$dir/$lib.lib"; then found=yes lib=$dir/$lib.lib break fi if test -f "$dir/lib$lib.a"; then found=yes lib=$dir/lib$lib.a break fi done IFS=$save_IFS if test "$found" != yes; then lib=$lib.lib fi } # func_cl_wrapper cl arg... # Adjust compile command to suit cl func_cl_wrapper () { # Assume a capable shell lib_path= shared=: linker_opts= for arg do if test -n "$eat"; then eat= else case $1 in -o) # configure might choose to run compile as 'compile cc -o foo foo.c'. eat=1 case $2 in *.o | *.[oO][bB][jJ]) func_file_conv "$2" set x "$@" -Fo"$file" shift ;; *) func_file_conv "$2" set x "$@" -Fe"$file" shift ;; esac ;; -I) eat=1 func_file_conv "$2" mingw set x "$@" -I"$file" shift ;; -I*) func_file_conv "${1#-I}" mingw set x "$@" -I"$file" shift ;; -l) eat=1 func_cl_dashl "$2" set x "$@" "$lib" shift ;; -l*) func_cl_dashl "${1#-l}" set x "$@" "$lib" shift ;; -L) eat=1 func_cl_dashL "$2" ;; -L*) func_cl_dashL "${1#-L}" ;; -static) shared=false ;; -Wl,*) arg=${1#-Wl,} save_ifs="$IFS"; IFS=',' for flag in $arg; do IFS="$save_ifs" linker_opts="$linker_opts $flag" done IFS="$save_ifs" ;; -Xlinker) eat=1 linker_opts="$linker_opts $2" ;; -*) set x "$@" "$1" shift ;; *.cc | *.CC | *.cxx | *.CXX | *.[cC]++) func_file_conv "$1" set x "$@" -Tp"$file" shift ;; *.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO]) func_file_conv "$1" mingw set x "$@" "$file" shift ;; *) set x "$@" "$1" shift ;; esac fi shift done if test -n "$linker_opts"; then linker_opts="-link$linker_opts" fi exec "$@" $linker_opts exit 1 } eat= case $1 in '') echo "$0: No command. Try '$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: compile [--help] [--version] PROGRAM [ARGS] Wrapper for compilers which do not understand '-c -o'. Remove '-o dest.o' from ARGS, run PROGRAM with the remaining arguments, and rename the output as expected. If you are trying to build a whole package this is not the right script to run: please start by reading the file 'INSTALL'. Report bugs to . EOF exit $? ;; -v | --v*) echo "compile $scriptversion" exit $? ;; cl | *[/\\]cl | cl.exe | *[/\\]cl.exe ) func_cl_wrapper "$@" # Doesn't return... ;; esac ofile= cfile= for arg do if test -n "$eat"; then eat= else case $1 in -o) # configure might choose to run compile as 'compile cc -o foo foo.c'. # So we strip '-o arg' only if arg is an object. eat=1 case $2 in *.o | *.obj) ofile=$2 ;; *) set x "$@" -o "$2" shift ;; esac ;; *.c) cfile=$1 set x "$@" "$1" shift ;; *) set x "$@" "$1" shift ;; esac fi shift done if test -z "$ofile" || test -z "$cfile"; then # If no '-o' option was seen then we might have been invoked from a # pattern rule where we don't need one. That is ok -- this is a # normal compilation that the losing compiler can handle. If no # '.c' file was seen then we are probably linking. That is also # ok. exec "$@" fi # Name of file we expect compiler to create. cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'` # Create the lock directory. # Note: use '[/\\:.-]' here to ensure that we don't use the same name # that we are using for the .o file. Also, base the name on the expected # object file name, since that is what matters with a parallel build. lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d while true; do if mkdir "$lockdir" >/dev/null 2>&1; then break fi sleep 1 done # FIXME: race condition here if user kills between mkdir and trap. trap "rmdir '$lockdir'; exit 1" 1 2 15 # Run the compile. "$@" ret=$? if test -f "$cofile"; then test "$cofile" = "$ofile" || mv "$cofile" "$ofile" elif test -f "${cofile}bj"; then test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile" fi rmdir "$lockdir" exit $ret # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: partclone-0.2.86/config.guess000077500000000000000000001235501262102574200161250ustar00rootroot00000000000000#! /bin/sh # Attempt to guess a canonical system name. # Copyright 1992-2014 Free Software Foundation, Inc. timestamp='2014-03-23' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # # Originally written by Per Bothner. # # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD # # Please send patches with a ChangeLog entry to config-patches@gnu.org. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright 1992-2014 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi trap 'exit 1' 1 2 15 # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. set_cc_for_build=' trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; : ${TMPDIR=/tmp} ; { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; dummy=$tmp/dummy ; tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; case $CC_FOR_BUILD,$HOST_CC,$CC in ,,) echo "int x;" > $dummy.c ; for c in cc gcc c89 c99 ; do if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then CC_FOR_BUILD="$c"; break ; fi ; done ; if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found ; fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac ; set_cc_for_build= ;' # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if (test -f /.attbin/uname) >/dev/null 2>&1 ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown case "${UNAME_SYSTEM}" in Linux|GNU|GNU/*) # If the system lacks a compiler, then just pick glibc. # We could probably try harder. LIBC=gnu eval $set_cc_for_build cat <<-EOF > $dummy.c #include #if defined(__UCLIBC__) LIBC=uclibc #elif defined(__dietlibc__) LIBC=dietlibc #else LIBC=gnu #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` ;; esac # Note: order is significant - the case branches are not exclusive. case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ /usr/sbin/$sysctl 2>/dev/null || echo unknown)` case "${UNAME_MACHINE_ARCH}" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently, or will in the future. case "${UNAME_MACHINE_ARCH}" in arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ELF__ then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case "${UNAME_VERSION}" in Debian*) release='-gnu' ;; *) release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}" exit ;; *:Bitrig:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE} exit ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} exit ;; *:ekkoBSD:*:*) echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} exit ;; *:SolidBSD:*:*) echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} exit ;; macppc:MirBSD:*:*) echo powerpc-unknown-mirbsd${UNAME_RELEASE} exit ;; *:MirBSD:*:*) echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} exit ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") UNAME_MACHINE="alpha" ;; "EV4.5 (21064)") UNAME_MACHINE="alpha" ;; "LCA4 (21066/21068)") UNAME_MACHINE="alpha" ;; "EV5 (21164)") UNAME_MACHINE="alphaev5" ;; "EV5.6 (21164A)") UNAME_MACHINE="alphaev56" ;; "EV5.6 (21164PC)") UNAME_MACHINE="alphapca56" ;; "EV5.7 (21164PC)") UNAME_MACHINE="alphapca57" ;; "EV6 (21264)") UNAME_MACHINE="alphaev6" ;; "EV6.7 (21264A)") UNAME_MACHINE="alphaev67" ;; "EV6.8CB (21264C)") UNAME_MACHINE="alphaev68" ;; "EV6.8AL (21264B)") UNAME_MACHINE="alphaev68" ;; "EV6.8CX (21264D)") UNAME_MACHINE="alphaev68" ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE="alphaev69" ;; "EV7 (21364)") UNAME_MACHINE="alphaev7" ;; "EV7.9 (21364A)") UNAME_MACHINE="alphaev79" ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` # Reset EXIT trap before exiting to avoid spurious non-zero exit code. exitcode=$? trap '' 0 exit $exitcode ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead # of the specific Alpha model? echo alpha-pc-interix exit ;; 21064:Windows_NT:50:3) echo alpha-dec-winnt3.5 exit ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit ;; *:[Aa]miga[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-amigaos exit ;; *:[Mm]orph[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-morphos exit ;; *:OS/390:*:*) echo i370-ibm-openedition exit ;; *:z/VM:*:*) echo s390-ibm-zvmoe exit ;; *:OS400:*:*) echo powerpc-ibm-os400 exit ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit ;; arm*:riscos:*:*|arm*:RISCOS:*:*) echo arm-unknown-riscos exit ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "`(/bin/universe) 2>/dev/null`" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd fi exit ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit ;; DRS?6000:unix:4.0:6*) echo sparc-icl-nx6 exit ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7; exit ;; esac ;; s390x:SunOS:*:*) echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) echo i386-pc-auroraux${UNAME_RELEASE} exit ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) eval $set_cc_for_build SUN_ARCH="i386" # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # This test works for both compilers. if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then SUN_ARCH="x86_64" fi fi echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` exit ;; sun3*:SunOS:*:*) echo m68k-sun-sunos${UNAME_RELEASE} exit ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos${UNAME_RELEASE} ;; sun4) echo sparc-sun-sunos${UNAME_RELEASE} ;; esac exit ;; aushp:SunOS:*:*) echo sparc-auspex-sunos${UNAME_RELEASE} exit ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint${UNAME_RELEASE} exit ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint${UNAME_RELEASE} exit ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint${UNAME_RELEASE} exit ;; m68k:machten:*:*) echo m68k-apple-machten${UNAME_RELEASE} exit ;; powerpc:machten:*:*) echo powerpc-apple-machten${UNAME_RELEASE} exit ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix${UNAME_RELEASE} exit ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix${UNAME_RELEASE} exit ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix${UNAME_RELEASE} exit ;; mips:*:*:UMIPS | mips:*:*:RISCos) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && SYSTEM_NAME=`$dummy $dummyarg` && { echo "$SYSTEM_NAME"; exit; } echo mips-mips-riscos${UNAME_RELEASE} exit ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax exit ;; Motorola:*:4.3:PL8-*) echo powerpc-harris-powermax exit ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) echo powerpc-harris-powermax exit ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix exit ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] then if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ [ ${TARGET_BINARY_INTERFACE}x = x ] then echo m88k-dg-dgux${UNAME_RELEASE} else echo m88k-dg-dguxbcs${UNAME_RELEASE} fi else echo i586-dg-dgux${UNAME_RELEASE} fi exit ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit ;; *:IRIX*:*:*) echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` exit ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit ;; ia64:AIX:*:*) if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} exit ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` then echo "$SYSTEM_NAME" else echo rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then echo rs6000-ibm-aix3.2.4 else echo rs6000-ibm-aix3.2 fi exit ;; *:AIX:*:[4567]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${IBM_ARCH}-ibm-aix${IBM_REV} exit ;; *:AIX:*:*) echo rs6000-ibm-aix exit ;; ibmrt:4.4BSD:*|romp-ibm:BSD:*) echo romp-ibm-bsd4.4 exit ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to exit ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` case "${UNAME_MACHINE}" in 9000/31? ) HP_ARCH=m68000 ;; 9000/[34]?? ) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in 32) HP_ARCH="hppa2.0n" ;; 64) HP_ARCH="hppa2.0w" ;; '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 esac ;; esac fi if [ "${HP_ARCH}" = "" ]; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if [ ${HP_ARCH} = "hppa2.0w" ] then eval $set_cc_for_build # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler # generating 64-bit code. GNU and HP use different nomenclature: # # $ CC_FOR_BUILD=cc ./config.guess # => hppa2.0w-hp-hpux11.23 # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | grep -q __LP64__ then HP_ARCH="hppa2.0w" else HP_ARCH="hppa64" fi fi echo ${HP_ARCH}-hp-hpux${HPUX_REV} exit ;; ia64:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux${HPUX_REV} exit ;; 3050*:HI-UX:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } echo unknown-hitachi-hiuxwe2 exit ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) echo hppa1.1-hp-bsd exit ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) echo hppa1.1-hp-osf exit ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo ${UNAME_MACHINE}-unknown-osf1mk else echo ${UNAME_MACHINE}-unknown-osf1 fi exit ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*[A-Z]90:*:*:*) echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; *:UNICOS/mp:*:*) echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} exit ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi${UNAME_RELEASE} exit ;; *:BSD/OS:*:*) echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit ;; *:FreeBSD:*:*) UNAME_PROCESSOR=`/usr/bin/uname -p` case ${UNAME_PROCESSOR} in amd64) echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; *) echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; esac exit ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit ;; *:MINGW64*:*) echo ${UNAME_MACHINE}-pc-mingw64 exit ;; *:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit ;; *:MSYS*:*) echo ${UNAME_MACHINE}-pc-msys exit ;; i*:windows32*:*) # uname -m includes "-pc" on this system. echo ${UNAME_MACHINE}-mingw32 exit ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit ;; *:Interix*:*) case ${UNAME_MACHINE} in x86) echo i586-pc-interix${UNAME_RELEASE} exit ;; authenticamd | genuineintel | EM64T) echo x86_64-unknown-interix${UNAME_RELEASE} exit ;; IA64) echo ia64-unknown-interix${UNAME_RELEASE} exit ;; esac ;; [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) echo i${UNAME_MACHINE}-pc-mks exit ;; 8664:Windows_NT:*) echo x86_64-pc-mks exit ;; i*:Windows_NT*:* | Pentium*:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we # UNAME_MACHINE based on the output of uname instead of i386? echo i586-pc-interix exit ;; i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin exit ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) echo x86_64-unknown-cygwin exit ;; p*:CYGWIN*:*) echo powerpcle-unknown-cygwin exit ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; *:GNU:*:*) # the GNU system echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC} exit ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit ;; aarch64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; aarch64_be:Linux:*:*) UNAME_MACHINE=aarch64_be echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep -q ld.so.1 if test "$?" = 0 ; then LIBC="gnulibc1" ; fi echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; arc:Linux:*:* | arceb:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; arm*:Linux:*:*) eval $set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then echo ${UNAME_MACHINE}-unknown-linux-${LIBC} else if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi else echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf fi fi exit ;; avr32*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; cris:Linux:*:*) echo ${UNAME_MACHINE}-axis-linux-${LIBC} exit ;; crisv32:Linux:*:*) echo ${UNAME_MACHINE}-axis-linux-${LIBC} exit ;; frv:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; hexagon:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; i*86:Linux:*:*) echo ${UNAME_MACHINE}-pc-linux-${LIBC} exit ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; m32r*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; m68*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; mips:Linux:*:* | mips64:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef ${UNAME_MACHINE} #undef ${UNAME_MACHINE}el #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=${UNAME_MACHINE}el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=${UNAME_MACHINE} #else CPU= #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; } ;; openrisc*:Linux:*:*) echo or1k-unknown-linux-${LIBC} exit ;; or32:Linux:*:* | or1k*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; padre:Linux:*:*) echo sparc-unknown-linux-${LIBC} exit ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-${LIBC} exit ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) echo hppa1.1-unknown-linux-${LIBC} ;; PA8*) echo hppa2.0-unknown-linux-${LIBC} ;; *) echo hppa-unknown-linux-${LIBC} ;; esac exit ;; ppc64:Linux:*:*) echo powerpc64-unknown-linux-${LIBC} exit ;; ppc:Linux:*:*) echo powerpc-unknown-linux-${LIBC} exit ;; ppc64le:Linux:*:*) echo powerpc64le-unknown-linux-${LIBC} exit ;; ppcle:Linux:*:*) echo powerpcle-unknown-linux-${LIBC} exit ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux-${LIBC} exit ;; sh64*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; tile*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; vax:Linux:*:*) echo ${UNAME_MACHINE}-dec-linux-${LIBC} exit ;; x86_64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; xtensa*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. echo i386-sequent-sysv4 exit ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. echo ${UNAME_MACHINE}-pc-os2-emx exit ;; i*86:XTS-300:*:STOP) echo ${UNAME_MACHINE}-unknown-stop exit ;; i*86:atheos:*:*) echo ${UNAME_MACHINE}-unknown-atheos exit ;; i*86:syllable:*:*) echo ${UNAME_MACHINE}-pc-syllable exit ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit ;; i*86:*DOS:*:*) echo ${UNAME_MACHINE}-pc-msdosdjgpp exit ;; i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} else echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} fi exit ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} exit ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo ${UNAME_MACHINE}-pc-sco$UNAME_REL else echo ${UNAME_MACHINE}-pc-sysv32 fi exit ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i586. # Note: whatever this is, it MUST be the same as what config.sub # prints for the "djgpp" host, or else GDB configury will decide that # this is a cross-build. echo i586-pc-msdosdjgpp exit ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit ;; paragon:*:*:*) echo i860-intel-osf1 exit ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 fi exit ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit ;; mc68k:UNIX:SYSTEM5:3.51m) echo m68k-convergent-sysv exit ;; M680?0:D-NIX:5.3:*) echo m68k-diab-dnix exit ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; NCR*:*:4.2:* | MPRAS*:*:4.2:*) OS_REL='.3' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos${UNAME_RELEASE} exit ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos${UNAME_RELEASE} exit ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos${UNAME_RELEASE} exit ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) echo powerpc-unknown-lynxos${UNAME_RELEASE} exit ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv${UNAME_RELEASE} exit ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` echo ${UNAME_MACHINE}-sni-sysv4 else echo ns32k-sni-sysv fi exit ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says echo i586-unisys-sysv4 exit ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. echo ${UNAME_MACHINE}-stratus-vos exit ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit ;; mc68*:A/UX:*:*) echo m68k-apple-aux${UNAME_RELEASE} exit ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then echo mips-nec-sysv${UNAME_RELEASE} else echo mips-unknown-sysv${UNAME_RELEASE} fi exit ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit ;; BePC:Haiku:*:*) # Haiku running on Intel PC compatible. echo i586-pc-haiku exit ;; x86_64:Haiku:*:*) echo x86_64-unknown-haiku exit ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux${UNAME_RELEASE} exit ;; SX-6:SUPER-UX:*:*) echo sx6-nec-superux${UNAME_RELEASE} exit ;; SX-7:SUPER-UX:*:*) echo sx7-nec-superux${UNAME_RELEASE} exit ;; SX-8:SUPER-UX:*:*) echo sx8-nec-superux${UNAME_RELEASE} exit ;; SX-8R:SUPER-UX:*:*) echo sx8r-nec-superux${UNAME_RELEASE} exit ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit ;; *:Rhapsody:*:*) echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} exit ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown eval $set_cc_for_build if test "$UNAME_PROCESSOR" = unknown ; then UNAME_PROCESSOR=powerpc fi if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then case $UNAME_PROCESSOR in i386) UNAME_PROCESSOR=x86_64 ;; powerpc) UNAME_PROCESSOR=powerpc64 ;; esac fi fi elif test "$UNAME_PROCESSOR" = i386 ; then # Avoid executing cc on OS X 10.9, as it ships with a stub # that puts up a graphical alert prompting to install # developer tools. Any system running Mac OS X 10.7 or # later (Darwin 11 and later) is required to have a 64-bit # processor. This is not true of the ARM version of Darwin # that Apple uses in portable devices. UNAME_PROCESSOR=x86_64 fi echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = "x86"; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} exit ;; *:QNX:*:4*) echo i386-pc-qnx exit ;; NEO-?:NONSTOP_KERNEL:*:*) echo neo-tandem-nsk${UNAME_RELEASE} exit ;; NSE-*:NONSTOP_KERNEL:*:*) echo nse-tandem-nsk${UNAME_RELEASE} exit ;; NSR-?:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk${UNAME_RELEASE} exit ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv exit ;; DS/*:UNIX_System_V:*:*) echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} exit ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "$cputype" = "386"; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi echo ${UNAME_MACHINE}-unknown-plan9 exit ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit ;; *:TENEX:*:*) echo pdp10-unknown-tenex exit ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 exit ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 exit ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 exit ;; *:ITS:*:*) echo pdp10-unknown-its exit ;; SEI:*:*:SEIUX) echo mips-sei-seiux${UNAME_RELEASE} exit ;; *:DragonFly:*:*) echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` case "${UNAME_MACHINE}" in A*) echo alpha-dec-vms ; exit ;; I*) echo ia64-dec-vms ; exit ;; V*) echo vax-dec-vms ; exit ;; esac ;; *:XENIX:*:SysV) echo i386-pc-xenix exit ;; i*86:skyos:*:*) echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' exit ;; i*86:rdos:*:*) echo ${UNAME_MACHINE}-pc-rdos exit ;; i*86:AROS:*:*) echo ${UNAME_MACHINE}-pc-aros exit ;; x86_64:VMkernel:*:*) echo ${UNAME_MACHINE}-unknown-esx exit ;; esac cat >&2 < in order to provide the needed information to handle your system. config.guess timestamp = $timestamp uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = ${UNAME_MACHINE} UNAME_RELEASE = ${UNAME_RELEASE} UNAME_SYSTEM = ${UNAME_SYSTEM} UNAME_VERSION = ${UNAME_VERSION} EOF exit 1 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: partclone-0.2.86/config.h.in000066400000000000000000000112741262102574200156270ustar00rootroot00000000000000/* config.h.in. Generated from configure.ac by autoheader. */ /* Define to 1 if translation of program messages to the user's native language is requested. */ #undef ENABLE_NLS /* Define to 1 if you have the header file. */ #undef HAVE_BLKID_BLKID_H /* Define to 1 if you have the MacOS X function CFLocaleCopyCurrent in the CoreFoundation framework. */ #undef HAVE_CFLOCALECOPYCURRENT /* Define to 1 if you have the MacOS X function CFPreferencesCopyAppValue in the CoreFoundation framework. */ #undef HAVE_CFPREFERENCESCOPYAPPVALUE /* Define to 1 if you have the header file. */ #undef HAVE_CTYPE_H /* Define if the GNU dcgettext() function is already present or preinstalled. */ #undef HAVE_DCGETTEXT /* Define to 1 if you have the header file. */ #undef HAVE_EXT2FS_EXT2FS_H /* Define to 1 if you have the header file. */ #undef HAVE_FCNTL_H /* Define if the GNU gettext() function is already present or preinstalled. */ #undef HAVE_GETTEXT /* Define to 1 if you have the header file. */ #undef HAVE_GRP_H /* Define if you have the iconv() function. */ #undef HAVE_ICONV /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_LIBINTL_H /* Define to 1 if you have the `ncursesw' library (-lncursesw). */ #undef HAVE_LIBNCURSESW /* Define to 1 if you have the `pthread' library (-lpthread). */ #undef HAVE_LIBPTHREAD /* Define to 1 if you have the header file. */ #undef HAVE_LIMITS_H /* Define to 1 if you have the header file. */ #undef HAVE_LINUX_MAGIC_H /* Define to 1 if you have the header file. */ #undef HAVE_LINUX_TYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_LOCALE_H /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H /* Define to 1 if you have the header file. */ #undef HAVE_MNTENT_H /* Define to 1 if you have the header file. */ #undef HAVE_MQUEUE_H /* Define to 1 if you have the header file. */ #undef HAVE_NCURSES_H /* Define to 1 if you have the header file. */ #undef HAVE_NILFS_H /* Define to 1 if you have the header file. */ #undef HAVE_NTFS_3G_MISC_H /* Define to 1 if you have the header file. */ #undef HAVE_NTFS_VERSION_H /* Define to 1 if you have the header file. */ #undef HAVE_PATHS_H /* Define to 1 if you have the header file. */ #undef HAVE_PWD_H /* Define to 1 if you have the header file. */ #undef HAVE_REISER4_LIBREISER4_H /* Define to 1 if you have the header file. */ #undef HAVE_REISERFS_REISERFS_H /* Define to 1 if you have the header file. */ #undef HAVE_SEMAPHORE_H /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H /* Define to 1 if you have the header file. */ #undef HAVE_SYSLOG_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_IOCTL_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_MOUNT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TIME_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_TIME_H /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* Name of package */ #undef PACKAGE /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT /* Define to the full name of this package. */ #undef PACKAGE_NAME /* Define to the full name and version of this package. */ #undef PACKAGE_STRING /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME /* Define to the home page for this package. */ #undef PACKAGE_URL /* Define to the version of this package. */ #undef PACKAGE_VERSION /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS /* Version number of package */ #undef VERSION /* Enable large inode numbers on Mac OS X 10.5. */ #ifndef _DARWIN_USE_64_BIT_INODE # define _DARWIN_USE_64_BIT_INODE 1 #endif /* Number of bits in a file offset, on hosts where this is settable. */ #undef _FILE_OFFSET_BITS /* Define for large files, on AIX-style hosts. */ #undef _LARGE_FILES partclone-0.2.86/config.rpath000077500000000000000000000374441262102574200161230ustar00rootroot00000000000000#! /bin/sh # Output a system dependent set of variables, describing how to set the # run time search path of shared libraries in an executable. # # Copyright 1996-2006 Free Software Foundation, Inc. # Taken from GNU libtool, 2001 # Originally by Gordon Matzigkeit , 1996 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # # The first argument passed to this file is the canonical host specification, # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # The environment variables CC, GCC, LDFLAGS, LD, with_gnu_ld # should be set by the caller. # # The set of defined variables is at the end of this script. # Known limitations: # - On IRIX 6.5 with CC="cc", the run time search patch must not be longer # than 256 bytes, otherwise the compiler driver will dump core. The only # known workaround is to choose shorter directory names for the build # directory and/or the installation directory. # All known linkers require a `.a' archive for static linking (except MSVC, # which needs '.lib'). libext=a shrext=.so host="$1" host_cpu=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` host_vendor=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` host_os=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` # Code taken from libtool.m4's _LT_CC_BASENAME. for cc_temp in $CC""; do case $cc_temp in compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; \-*) ;; *) break;; esac done cc_basename=`echo "$cc_temp" | sed -e 's%^.*/%%'` # Code taken from libtool.m4's AC_LIBTOOL_PROG_COMPILER_PIC. wl= if test "$GCC" = yes; then wl='-Wl,' else case "$host_os" in aix*) wl='-Wl,' ;; darwin*) case $cc_basename in xlc*) wl='-Wl,' ;; esac ;; mingw* | pw32* | os2*) ;; hpux9* | hpux10* | hpux11*) wl='-Wl,' ;; irix5* | irix6* | nonstopux*) wl='-Wl,' ;; newsos6) ;; linux*) case $cc_basename in icc* | ecc*) wl='-Wl,' ;; pgcc | pgf77 | pgf90) wl='-Wl,' ;; ccc*) wl='-Wl,' ;; como) wl='-lopt=' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) wl='-Wl,' ;; esac ;; esac ;; osf3* | osf4* | osf5*) wl='-Wl,' ;; sco3.2v5*) ;; solaris*) wl='-Wl,' ;; sunos4*) wl='-Qoption ld ' ;; sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) wl='-Wl,' ;; sysv4*MP*) ;; unicos*) wl='-Wl,' ;; uts4*) ;; esac fi # Code taken from libtool.m4's AC_LIBTOOL_PROG_LD_SHLIBS. hardcode_libdir_flag_spec= hardcode_libdir_separator= hardcode_direct=no hardcode_minus_L=no case "$host_os" in cygwin* | mingw* | pw32*) # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. if test "$GCC" != yes; then with_gnu_ld=no fi ;; interix*) # we just hope/assume this is gcc and not c89 (= MSVC++) with_gnu_ld=yes ;; openbsd*) with_gnu_ld=no ;; esac ld_shlibs=yes if test "$with_gnu_ld" = yes; then # Set some defaults for GNU ld with shared library support. These # are reset later if shared libraries are not supported. Putting them # here allows them to be overridden if necessary. # Unlike libtool, we use -rpath here, not --rpath, since the documented # option of GNU ld is called -rpath, not --rpath. hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' case "$host_os" in aix3* | aix4* | aix5*) # On AIX/PPC, the GNU linker is very broken if test "$host_cpu" != ia64; then ld_shlibs=no fi ;; amigaos*) hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes # Samuel A. Falvo II reports # that the semantics of dynamic libraries on AmigaOS, at least up # to version 4, is to share data among multiple programs linked # with the same dynamic library. Since this doesn't match the # behavior of shared libraries on other platforms, we cannot use # them. ld_shlibs=no ;; beos*) if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then : else ld_shlibs=no fi ;; cygwin* | mingw* | pw32*) # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. hardcode_libdir_flag_spec='-L$libdir' if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then : else ld_shlibs=no fi ;; interix3*) hardcode_direct=no hardcode_libdir_flag_spec='${wl}-rpath,$libdir' ;; linux*) if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then : else ld_shlibs=no fi ;; netbsd*) ;; solaris*) if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then ld_shlibs=no elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then : else ld_shlibs=no fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) case `$LD -v 2>&1` in *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) ld_shlibs=no ;; *) if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`' else ld_shlibs=no fi ;; esac ;; sunos4*) hardcode_direct=yes ;; *) if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then : else ld_shlibs=no fi ;; esac if test "$ld_shlibs" = no; then hardcode_libdir_flag_spec= fi else case "$host_os" in aix3*) # Note: this linker hardcodes the directories in LIBPATH if there # are no directories specified by -L. hardcode_minus_L=yes if test "$GCC" = yes; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. hardcode_direct=unsupported fi ;; aix4* | aix5*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no else aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[23]|aix4.[23].*|aix5*) for ld_flag in $LDFLAGS; do if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then aix_use_runtimelinking=yes break fi done ;; esac fi hardcode_direct=yes hardcode_libdir_separator=':' if test "$GCC" = yes; then case $host_os in aix4.[012]|aix4.[012].*) collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && \ strings "$collect2name" | grep resolve_lib_name >/dev/null then # We have reworked collect2 hardcode_direct=yes else # We have old collect2 hardcode_direct=unsupported hardcode_minus_L=yes hardcode_libdir_flag_spec='-L$libdir' hardcode_libdir_separator= fi ;; esac fi # Begin _LT_AC_SYS_LIBPATH_AIX. echo 'int main () { return 0; }' > conftest.c ${CC} ${LDFLAGS} conftest.c -o conftest aix_libpath=`dump -H conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'` if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'` fi if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib" fi rm -f conftest.c conftest # End _LT_AC_SYS_LIBPATH_AIX. if test "$aix_use_runtimelinking" = yes; then hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" else if test "$host_cpu" = ia64; then hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' else hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" fi fi ;; amigaos*) hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes # see comment about different semantics on the GNU ld section ld_shlibs=no ;; bsdi[45]*) ;; cygwin* | mingw* | pw32*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. hardcode_libdir_flag_spec=' ' libext=lib ;; darwin* | rhapsody*) hardcode_direct=no if test "$GCC" = yes ; then : else case $cc_basename in xlc*) ;; *) ld_shlibs=no ;; esac fi ;; dgux*) hardcode_libdir_flag_spec='-L$libdir' ;; freebsd1*) ld_shlibs=no ;; freebsd2.2*) hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes ;; freebsd2*) hardcode_direct=yes hardcode_minus_L=yes ;; freebsd* | kfreebsd*-gnu | dragonfly*) hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes ;; hpux9*) hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_separator=: hardcode_direct=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes ;; hpux10*) if test "$with_gnu_ld" = no; then hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_separator=: hardcode_direct=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes fi ;; hpux11*) if test "$with_gnu_ld" = no; then hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_separator=: case $host_cpu in hppa*64*|ia64*) hardcode_direct=no ;; *) hardcode_direct=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes ;; esac fi ;; irix5* | irix6* | nonstopux*) hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: ;; netbsd*) hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes ;; newsos6) hardcode_direct=yes hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: ;; openbsd*) hardcode_direct=yes if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then hardcode_libdir_flag_spec='${wl}-rpath,$libdir' else case "$host_os" in openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) hardcode_libdir_flag_spec='-R$libdir' ;; *) hardcode_libdir_flag_spec='${wl}-rpath,$libdir' ;; esac fi ;; os2*) hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes ;; osf3*) hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: ;; osf4* | osf5*) if test "$GCC" = yes; then hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' else # Both cc and cxx compiler support -rpath directly hardcode_libdir_flag_spec='-rpath $libdir' fi hardcode_libdir_separator=: ;; solaris*) hardcode_libdir_flag_spec='-R$libdir' ;; sunos4*) hardcode_libdir_flag_spec='-L$libdir' hardcode_direct=yes hardcode_minus_L=yes ;; sysv4) case $host_vendor in sni) hardcode_direct=yes # is this really true??? ;; siemens) hardcode_direct=no ;; motorola) hardcode_direct=no #Motorola manual says yes, but my tests say they lie ;; esac ;; sysv4.3*) ;; sysv4*MP*) if test -d /usr/nec; then ld_shlibs=yes fi ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7*) ;; sysv5* | sco3.2v5* | sco5v6*) hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`' hardcode_libdir_separator=':' ;; uts4*) hardcode_libdir_flag_spec='-L$libdir' ;; *) ld_shlibs=no ;; esac fi # Check dynamic linker characteristics # Code taken from libtool.m4's AC_LIBTOOL_SYS_DYNAMIC_LINKER. libname_spec='lib$name' case "$host_os" in aix3*) ;; aix4* | aix5*) ;; amigaos*) ;; beos*) ;; bsdi[45]*) ;; cygwin* | mingw* | pw32*) shrext=.dll ;; darwin* | rhapsody*) shrext=.dylib ;; dgux*) ;; freebsd1*) ;; kfreebsd*-gnu) ;; freebsd* | dragonfly*) ;; gnu*) ;; hpux9* | hpux10* | hpux11*) case $host_cpu in ia64*) shrext=.so ;; hppa*64*) shrext=.sl ;; *) shrext=.sl ;; esac ;; interix3*) ;; irix5* | irix6* | nonstopux*) case "$host_os" in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= ;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 ;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 ;; *) libsuff= shlibsuff= ;; esac ;; esac ;; linux*oldld* | linux*aout* | linux*coff*) ;; linux*) ;; knetbsd*-gnu) ;; netbsd*) ;; newsos6) ;; nto-qnx*) ;; openbsd*) ;; os2*) libname_spec='$name' shrext=.dll ;; osf3* | osf4* | osf5*) ;; solaris*) ;; sunos4*) ;; sysv4 | sysv4.3*) ;; sysv4*MP*) ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) ;; uts4*) ;; esac sed_quote_subst='s/\(["`$\\]\)/\\\1/g' escaped_wl=`echo "X$wl" | sed -e 's/^X//' -e "$sed_quote_subst"` shlibext=`echo "$shrext" | sed -e 's,^\.,,'` escaped_hardcode_libdir_flag_spec=`echo "X$hardcode_libdir_flag_spec" | sed -e 's/^X//' -e "$sed_quote_subst"` LC_ALL=C sed -e 's/^\([a-zA-Z0-9_]*\)=/acl_cv_\1=/' <. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # Please send patches with a ChangeLog entry to config-patches@gnu.org. # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS $0 [OPTION] ALIAS Canonicalize a configuration name. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright 1992-2014 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" exit 1 ;; *local*) # First pass through any local machine types. echo $1 exit ;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ knetbsd*-gnu* | netbsd*-gnu* | \ kopensolaris*-gnu* | \ storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; android-linux) os=-linux-android basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] then os=`echo $1 | sed 's/.*-/-/'` else os=; fi ;; esac ### Let's recognize common machines as not being operating systems so ### that things like config.sub decstation-3100 work. We also ### recognize some manufacturers as not being operating systems, so we ### can provide default operating systems below. case $os in -sun*os*) # Prevent following clause from handling this invalid input. ;; -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ -apple | -axis | -knuth | -cray | -microblaze*) os= basic_machine=$1 ;; -bluegene*) os=-cnk ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 ;; -scout) ;; -wrs) os=-vxworks basic_machine=$1 ;; -chorusos*) os=-chorusos basic_machine=$1 ;; -chorusrdb) os=-chorusrdb basic_machine=$1 ;; -hiux*) os=-hiuxwe2 ;; -sco6) os=-sco5v6 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5) os=-sco3.2v5 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco4) os=-sco3.2v4 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2.[4-9]*) os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2v[4-9]*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5v6*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco*) os=-sco3.2v2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -udk*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -isc) os=-isc2.2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -clix*) basic_machine=clipper-intergraph ;; -isc*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -lynx*178) os=-lynxos178 ;; -lynx*5) os=-lynxos5 ;; -lynx*) os=-lynxos ;; -ptx*) basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` ;; -windowsnt*) os=`echo $os | sed -e 's/windowsnt/winnt/'` ;; -psos*) os=-psos ;; -mint | -mint[0-9]*) basic_machine=m68k-atari os=-mint ;; esac # Decode aliases for certain CPU-COMPANY combinations. case $basic_machine in # Recognize the basic CPU types without company name. # Some are omitted here because they have special meanings below. 1750a | 580 \ | a29k \ | aarch64 | aarch64_be \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | am33_2.0 \ | arc | arceb \ | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ | avr | avr32 \ | be32 | be64 \ | bfin \ | c4x | c8051 | clipper \ | d10v | d30v | dlx | dsp16xx \ | epiphany \ | fido | fr30 | frv \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | hexagon \ | i370 | i860 | i960 | ia64 \ | ip2k | iq2000 \ | k1om \ | le32 | le64 \ | lm32 \ | m32c | m32r | m32rle | m68000 | m68k | m88k \ | maxq | mb | microblaze | microblazeel | mcore | mep | metag \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ | mips64octeon | mips64octeonel \ | mips64orion | mips64orionel \ | mips64r5900 | mips64r5900el \ | mips64vr | mips64vrel \ | mips64vr4100 | mips64vr4100el \ | mips64vr4300 | mips64vr4300el \ | mips64vr5000 | mips64vr5000el \ | mips64vr5900 | mips64vr5900el \ | mipsisa32 | mipsisa32el \ | mipsisa32r2 | mipsisa32r2el \ | mipsisa32r6 | mipsisa32r6el \ | mipsisa64 | mipsisa64el \ | mipsisa64r2 | mipsisa64r2el \ | mipsisa64r6 | mipsisa64r6el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipsr5900 | mipsr5900el \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ | moxie \ | mt \ | msp430 \ | nds32 | nds32le | nds32be \ | nios | nios2 | nios2eb | nios2el \ | ns16k | ns32k \ | open8 | or1k | or1knd | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle \ | pyramid \ | riscv32 | riscv64 \ | rl78 | rx \ | score \ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ | spu \ | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ | ubicom32 \ | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ | we32k \ | x86 | xc16x | xstormy16 | xtensa \ | z8k | z80) basic_machine=$basic_machine-unknown ;; c54x) basic_machine=tic54x-unknown ;; c55x) basic_machine=tic55x-unknown ;; c6x) basic_machine=tic6x-unknown ;; m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip) basic_machine=$basic_machine-unknown os=-none ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) ;; ms1) basic_machine=mt-unknown ;; strongarm | thumb | xscale) basic_machine=arm-unknown ;; xgate) basic_machine=$basic_machine-unknown os=-none ;; xscaleeb) basic_machine=armeb-unknown ;; xscaleel) basic_machine=armel-unknown ;; # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. i*86 | x86_64) basic_machine=$basic_machine-pc ;; # Object if more than one company name word. *-*-*) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; # Recognize the basic CPU types with company name. 580-* \ | a29k-* \ | aarch64-* | aarch64_be-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* | avr32-* \ | be32-* | be64-* \ | bfin-* | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* \ | c8051-* | clipper-* | craynv-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | elxsi-* \ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | hexagon-* \ | i*86-* | i860-* | i960-* | ia64-* \ | ip2k-* | iq2000-* \ | k1om-* \ | le32-* | le64-* \ | lm32-* \ | m32c-* | m32r-* | m32rle-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ | microblaze-* | microblazeel-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ | mips64octeon-* | mips64octeonel-* \ | mips64orion-* | mips64orionel-* \ | mips64r5900-* | mips64r5900el-* \ | mips64vr-* | mips64vrel-* \ | mips64vr4100-* | mips64vr4100el-* \ | mips64vr4300-* | mips64vr4300el-* \ | mips64vr5000-* | mips64vr5000el-* \ | mips64vr5900-* | mips64vr5900el-* \ | mipsisa32-* | mipsisa32el-* \ | mipsisa32r2-* | mipsisa32r2el-* \ | mipsisa32r6-* | mipsisa32r6el-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64r2-* | mipsisa64r2el-* \ | mipsisa64r6-* | mipsisa64r6el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ | mipsr5900-* | mipsr5900el-* \ | mipstx39-* | mipstx39el-* \ | mmix-* \ | mt-* \ | msp430-* \ | nds32-* | nds32le-* | nds32be-* \ | nios-* | nios2-* | nios2eb-* | nios2el-* \ | none-* | np1-* | ns16k-* | ns32k-* \ | open8-* \ | or1k*-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ | pyramid-* \ | rl78-* | romp-* | rs6000-* | rx-* \ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ | sparclite-* \ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \ | tahoe-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ | tile*-* \ | tron-* \ | ubicom32-* \ | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ | vax-* \ | we32k-* \ | x86-* | x86_64-* | xc16x-* | xps100-* \ | xstormy16-* | xtensa*-* \ | ymp-* \ | z8k-* | z80-*) ;; # Recognize the basic CPU types without company name, with glob match. xtensa*) basic_machine=$basic_machine-unknown ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 386bsd) basic_machine=i386-unknown os=-bsd ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) basic_machine=m68000-att ;; 3b*) basic_machine=we32k-att ;; a29khif) basic_machine=a29k-amd os=-udi ;; abacus) basic_machine=abacus-unknown ;; adobe68k) basic_machine=m68010-adobe os=-scout ;; alliant | fx80) basic_machine=fx80-alliant ;; altos | altos3068) basic_machine=m68k-altos ;; am29k) basic_machine=a29k-none os=-bsd ;; amd64) basic_machine=x86_64-pc ;; amd64-*) basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; amdahl) basic_machine=580-amdahl os=-sysv ;; amiga | amiga-*) basic_machine=m68k-unknown ;; amigaos | amigados) basic_machine=m68k-unknown os=-amigaos ;; amigaunix | amix) basic_machine=m68k-unknown os=-sysv4 ;; apollo68) basic_machine=m68k-apollo os=-sysv ;; apollo68bsd) basic_machine=m68k-apollo os=-bsd ;; aros) basic_machine=i386-pc os=-aros ;; aux) basic_machine=m68k-apple os=-aux ;; balance) basic_machine=ns32k-sequent os=-dynix ;; blackfin) basic_machine=bfin-unknown os=-linux ;; blackfin-*) basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; bluegene*) basic_machine=powerpc-ibm os=-cnk ;; c54x-*) basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c55x-*) basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c6x-*) basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c90) basic_machine=c90-cray os=-unicos ;; cegcc) basic_machine=arm-unknown os=-cegcc ;; convex-c1) basic_machine=c1-convex os=-bsd ;; convex-c2) basic_machine=c2-convex os=-bsd ;; convex-c32) basic_machine=c32-convex os=-bsd ;; convex-c34) basic_machine=c34-convex os=-bsd ;; convex-c38) basic_machine=c38-convex os=-bsd ;; cray | j90) basic_machine=j90-cray os=-unicos ;; craynv) basic_machine=craynv-cray os=-unicosmp ;; cr16 | cr16-*) basic_machine=cr16-unknown os=-elf ;; crds | unos) basic_machine=m68k-crds ;; crisv32 | crisv32-* | etraxfs*) basic_machine=crisv32-axis ;; cris | cris-* | etrax*) basic_machine=cris-axis ;; crx) basic_machine=crx-unknown os=-elf ;; da30 | da30-*) basic_machine=m68k-da30 ;; decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) basic_machine=mips-dec ;; decsystem10* | dec10*) basic_machine=pdp10-dec os=-tops10 ;; decsystem20* | dec20*) basic_machine=pdp10-dec os=-tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; delta88) basic_machine=m88k-motorola os=-sysv3 ;; dicos) basic_machine=i686-pc os=-dicos ;; djgpp) basic_machine=i586-pc os=-msdosdjgpp ;; dpx20 | dpx20-*) basic_machine=rs6000-bull os=-bosx ;; dpx2* | dpx2*-bull) basic_machine=m68k-bull os=-sysv3 ;; ebmon29k) basic_machine=a29k-amd os=-ebmon ;; elxsi) basic_machine=elxsi-elxsi os=-bsd ;; encore | umax | mmax) basic_machine=ns32k-encore ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson os=-ose ;; fx2800) basic_machine=i860-alliant ;; genix) basic_machine=ns32k-ns ;; gmicro) basic_machine=tron-gmicro os=-sysv ;; go32) basic_machine=i386-pc os=-go32 ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; h8300hms) basic_machine=h8300-hitachi os=-hms ;; h8300xray) basic_machine=h8300-hitachi os=-xray ;; h8500hms) basic_machine=h8500-hitachi os=-hms ;; harris) basic_machine=m88k-harris os=-sysv3 ;; hp300-*) basic_machine=m68k-hp ;; hp300bsd) basic_machine=m68k-hp os=-bsd ;; hp300hpux) basic_machine=m68k-hp os=-hpux ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) basic_machine=m68000-hp ;; hp9k3[2-9][0-9]) basic_machine=m68k-hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) basic_machine=hppa1.1-hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) basic_machine=hppa1.1-hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; hppa-next) os=-nextstep3 ;; hppaosf) basic_machine=hppa1.1-hp os=-osf ;; hppro) basic_machine=hppa1.1-hp os=-proelf ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; i*86v4*) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv4 ;; i*86v) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv ;; i*86sol2) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-solaris2 ;; i386mach) basic_machine=i386-mach os=-mach ;; i386-vsta | vsta) basic_machine=i386-unknown os=-vsta ;; iris | iris4d) basic_machine=mips-sgi case $os in -irix*) ;; *) os=-irix4 ;; esac ;; isi68 | isi) basic_machine=m68k-isi os=-sysv ;; m68knommu) basic_machine=m68k-unknown os=-linux ;; m68knommu-*) basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; m88k-omron*) basic_machine=m88k-omron ;; magnum | m3230) basic_machine=mips-mips os=-sysv ;; merlin) basic_machine=ns32k-utek os=-sysv ;; microblaze*) basic_machine=microblaze-xilinx ;; mingw64) basic_machine=x86_64-pc os=-mingw64 ;; mingw32) basic_machine=i686-pc os=-mingw32 ;; mingw32ce) basic_machine=arm-unknown os=-mingw32ce ;; miniframe) basic_machine=m68000-convergent ;; *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari os=-mint ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; mips3*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown ;; monitor) basic_machine=m68k-rom68k os=-coff ;; morphos) basic_machine=powerpc-unknown os=-morphos ;; moxiebox) basic_machine=moxie-unknown os=-moxiebox ;; msdos) basic_machine=i386-pc os=-msdos ;; ms1-*) basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` ;; msys) basic_machine=i686-pc os=-msys ;; mvs) basic_machine=i370-ibm os=-mvs ;; nacl) basic_machine=le32-unknown os=-nacl ;; ncr3000) basic_machine=i486-ncr os=-sysv4 ;; netbsd386) basic_machine=i386-unknown os=-netbsd ;; netwinder) basic_machine=armv4l-rebel os=-linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony os=-newsos ;; news1000) basic_machine=m68030-sony os=-newsos ;; news-3600 | risc-news) basic_machine=mips-sony os=-newsos ;; necv70) basic_machine=v70-nec os=-sysv ;; next | m*-next ) basic_machine=m68k-next case $os in -nextstep* ) ;; -ns2*) os=-nextstep2 ;; *) os=-nextstep3 ;; esac ;; nh3000) basic_machine=m68k-harris os=-cxux ;; nh[45]000) basic_machine=m88k-harris os=-cxux ;; nindy960) basic_machine=i960-intel os=-nindy ;; mon960) basic_machine=i960-intel os=-mon960 ;; nonstopux) basic_machine=mips-compaq os=-nonstopux ;; np1) basic_machine=np1-gould ;; neo-tandem) basic_machine=neo-tandem ;; nse-tandem) basic_machine=nse-tandem ;; nsr-tandem) basic_machine=nsr-tandem ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf ;; openrisc | openrisc-*) basic_machine=or32-unknown ;; os400) basic_machine=powerpc-ibm os=-os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=-ose ;; os68k) basic_machine=m68k-none os=-os68k ;; pa-hitachi) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; paragon) basic_machine=i860-intel os=-osf ;; parisc) basic_machine=hppa-unknown os=-linux ;; parisc-*) basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; pbd) basic_machine=sparc-tti ;; pbb) basic_machine=m68k-tti ;; pc532 | pc532-*) basic_machine=ns32k-pc532 ;; pc98) basic_machine=i386-pc ;; pc98-*) basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium | p5 | k5 | k6 | nexgen | viac3) basic_machine=i586-pc ;; pentiumpro | p6 | 6x86 | athlon | athlon_*) basic_machine=i686-pc ;; pentiumii | pentium2 | pentiumiii | pentium3) basic_machine=i686-pc ;; pentium4) basic_machine=i786-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium4-*) basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould ;; power) basic_machine=power-ibm ;; ppc | ppcbe) basic_machine=powerpc-unknown ;; ppc-* | ppcbe-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle | ppc-le | powerpc-little) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64) basic_machine=powerpc64-unknown ;; ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64le | powerpc64little | ppc64-le | powerpc64-little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ps2) basic_machine=i386-ibm ;; pw32) basic_machine=i586-unknown os=-pw32 ;; rdos | rdos64) basic_machine=x86_64-pc os=-rdos ;; rdos32) basic_machine=i386-pc os=-rdos ;; rom68k) basic_machine=m68k-rom68k os=-coff ;; rm[46]00) basic_machine=mips-siemens ;; rtpc | rtpc-*) basic_machine=romp-ibm ;; s390 | s390-*) basic_machine=s390-ibm ;; s390x | s390x-*) basic_machine=s390x-ibm ;; sa29200) basic_machine=a29k-amd os=-udi ;; sb1) basic_machine=mipsisa64sb1-unknown ;; sb1el) basic_machine=mipsisa64sb1el-unknown ;; sde) basic_machine=mipsisa32-sde os=-elf ;; sei) basic_machine=mips-sei os=-seiux ;; sequent) basic_machine=i386-sequent ;; sh) basic_machine=sh-hitachi os=-hms ;; sh5el) basic_machine=sh5le-unknown ;; sh64) basic_machine=sh64-unknown ;; sparclite-wrs | simso-wrs) basic_machine=sparclite-wrs os=-vxworks ;; sps7) basic_machine=m68k-bull os=-sysv2 ;; spur) basic_machine=spur-unknown ;; st2000) basic_machine=m68k-tandem ;; stratus) basic_machine=i860-stratus os=-sysv4 ;; strongarm-* | thumb-*) basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` ;; sun2) basic_machine=m68000-sun ;; sun2os3) basic_machine=m68000-sun os=-sunos3 ;; sun2os4) basic_machine=m68000-sun os=-sunos4 ;; sun3os3) basic_machine=m68k-sun os=-sunos3 ;; sun3os4) basic_machine=m68k-sun os=-sunos4 ;; sun4os3) basic_machine=sparc-sun os=-sunos3 ;; sun4os4) basic_machine=sparc-sun os=-sunos4 ;; sun4sol2) basic_machine=sparc-sun os=-solaris2 ;; sun3 | sun3-*) basic_machine=m68k-sun ;; sun4) basic_machine=sparc-sun ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun ;; sv1) basic_machine=sv1-cray os=-unicos ;; symmetry) basic_machine=i386-sequent os=-dynix ;; t3e) basic_machine=alphaev5-cray os=-unicos ;; t90) basic_machine=t90-cray os=-unicos ;; tile*) basic_machine=$basic_machine-unknown os=-linux-gnu ;; tx39) basic_machine=mipstx39-unknown ;; tx39el) basic_machine=mipstx39el-unknown ;; toad1) basic_machine=pdp10-xkl os=-tops20 ;; tower | tower-32) basic_machine=m68k-ncr ;; tpf) basic_machine=s390x-ibm os=-tpf ;; udi29k) basic_machine=a29k-amd os=-udi ;; ultra3) basic_machine=a29k-nyu os=-sym1 ;; v810 | necv810) basic_machine=v810-nec os=-none ;; vaxv) basic_machine=vax-dec os=-sysv ;; vms) basic_machine=vax-dec os=-vms ;; vpp*|vx|vx-*) basic_machine=f301-fujitsu ;; vxworks960) basic_machine=i960-wrs os=-vxworks ;; vxworks68) basic_machine=m68k-wrs os=-vxworks ;; vxworks29k) basic_machine=a29k-wrs os=-vxworks ;; w65*) basic_machine=w65-wdc os=-none ;; w89k-*) basic_machine=hppa1.1-winbond os=-proelf ;; xbox) basic_machine=i686-pc os=-mingw32 ;; xps | xps100) basic_machine=xps100-honeywell ;; xscale-* | xscalee[bl]-*) basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` ;; ymp) basic_machine=ymp-cray os=-unicos ;; z8k-*-coff) basic_machine=z8k-unknown os=-sim ;; z80-*-coff) basic_machine=z80-unknown os=-sim ;; none) basic_machine=none-none os=-none ;; # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) basic_machine=hppa1.1-winbond ;; op50n) basic_machine=hppa1.1-oki ;; op60c) basic_machine=hppa1.1-oki ;; romp) basic_machine=romp-ibm ;; mmix) basic_machine=mmix-knuth ;; rs6000) basic_machine=rs6000-ibm ;; vax) basic_machine=vax-dec ;; pdp10) # there are many clones, so DEC is not a safe bet basic_machine=pdp10-unknown ;; pdp11) basic_machine=pdp11-dec ;; we32k) basic_machine=we32k-att ;; sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) basic_machine=sh-unknown ;; sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) basic_machine=sparc-sun ;; cydra) basic_machine=cydra-cydrome ;; orion) basic_machine=orion-highlevel ;; orion105) basic_machine=clipper-highlevel ;; mac | mpw | mac-mpw) basic_machine=m68k-apple ;; pmac | pmac-mpw) basic_machine=powerpc-apple ;; *-unknown) # Make sure to match an already-canonicalized machine name. ;; *) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; esac # Here we canonicalize certain aliases for manufacturers. case $basic_machine in *-digital*) basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` ;; *-commodore*) basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if [ x"$os" != x"" ] then case $os in # First match some system type aliases # that might get confused with valid system types. # -solaris* is a basic system type, with this one exception. -auroraux) os=-auroraux ;; -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; -solaris) os=-solaris2 ;; -svr4*) os=-sysv4 ;; -unixware*) os=-sysv4.2uw ;; -gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; # First accept the basic system types. # The portable systems comes first. # Each alternative MUST END IN A *, to match a version number. # -sysv* is not here because it comes later, after sysvr4. -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ | -sym* | -kopensolaris* | -plan9* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* | -aros* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ | -bitrig* | -openbsd* | -solidbsd* \ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* | -cegcc* \ | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ | -linux-newlib* | -linux-musl* | -linux-uclibc* \ | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* | -tirtos*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) case $basic_machine in x86-* | i*86-*) ;; *) os=-nto$os ;; esac ;; -nto-qnx*) ;; -nto*) os=`echo $os | sed -e 's|nto|nto-qnx|'` ;; -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) ;; -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; -linux-dietlibc) os=-linux-dietlibc ;; -linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; -sunos5*) os=`echo $os | sed -e 's|sunos5|solaris2|'` ;; -sunos6*) os=`echo $os | sed -e 's|sunos6|solaris3|'` ;; -opened*) os=-openedition ;; -os400*) os=-os400 ;; -wince*) os=-wince ;; -osfrose*) os=-osfrose ;; -osf*) os=-osf ;; -utek*) os=-bsd ;; -dynix*) os=-bsd ;; -acis*) os=-aos ;; -atheos*) os=-atheos ;; -syllable*) os=-syllable ;; -386bsd) os=-bsd ;; -ctix* | -uts*) os=-sysv ;; -nova*) os=-rtmk-nova ;; -ns2 ) os=-nextstep2 ;; -nsk*) os=-nsk ;; # Preserve the version number of sinix5. -sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; -sinix*) os=-sysv4 ;; -tpf*) os=-tpf ;; -triton*) os=-sysv3 ;; -oss*) os=-sysv3 ;; -svr4) os=-sysv4 ;; -svr3) os=-sysv3 ;; -sysvr4) os=-sysv4 ;; # This must come after -sysvr4. -sysv*) ;; -ose*) os=-ose ;; -es1800*) os=-ose ;; -xenix) os=-xenix ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) os=-mint ;; -aros*) os=-aros ;; -zvmoe) os=-zvmoe ;; -dicos*) os=-dicos ;; -nacl*) ;; -none) ;; *) # Get rid of the `-' at the beginning of $os. os=`echo $os | sed 's/[^-]*-//'` echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 exit 1 ;; esac else # Here we handle the default operating systems that come with various machines. # The value should be what the vendor currently ships out the door with their # machine or put another way, the most popular os provided with the machine. # Note that if you're going to try to match "-MANUFACTURER" here (say, # "-sun"), then you have to tell the case statement up towards the top # that MANUFACTURER isn't an operating system. Otherwise, code above # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. case $basic_machine in score-*) os=-elf ;; spu-*) os=-elf ;; *-acorn) os=-riscix1.2 ;; arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; c4x-* | tic4x-*) os=-coff ;; c8051-*) os=-elf ;; hexagon-*) os=-elf ;; tic54x-*) os=-coff ;; tic55x-*) os=-coff ;; tic6x-*) os=-coff ;; # This must come before the *-dec entry. pdp10-*) os=-tops20 ;; pdp11-*) os=-none ;; *-dec | vax-*) os=-ultrix4.2 ;; m68*-apollo) os=-domain ;; i386-sun) os=-sunos4.0.2 ;; m68000-sun) os=-sunos3 ;; m68*-cisco) os=-aout ;; mep-*) os=-elf ;; mips*-cisco) os=-elf ;; mips*-*) os=-elf ;; or32-*) os=-coff ;; *-tti) # must be before sparc entry or we get the wrong os. os=-sysv3 ;; sparc-* | *-sun) os=-sunos4.1.1 ;; *-be) os=-beos ;; *-haiku) os=-haiku ;; *-ibm) os=-aix ;; *-knuth) os=-mmixware ;; *-wec) os=-proelf ;; *-winbond) os=-proelf ;; *-oki) os=-proelf ;; *-hp) os=-hpux ;; *-hitachi) os=-hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) os=-sysv ;; *-cbm) os=-amigaos ;; *-dg) os=-dgux ;; *-dolphin) os=-sysv3 ;; m68k-ccur) os=-rtu ;; m88k-omron*) os=-luna ;; *-next ) os=-nextstep ;; *-sequent) os=-ptx ;; *-crds) os=-unos ;; *-ns) os=-genix ;; i370-*) os=-mvs ;; *-next) os=-nextstep3 ;; *-gould) os=-sysv ;; *-highlevel) os=-bsd ;; *-encore) os=-bsd ;; *-sgi) os=-irix ;; *-siemens) os=-sysv4 ;; *-masscomp) os=-rtu ;; f30[01]-fujitsu | f700-fujitsu) os=-uxpv ;; *-rom68k) os=-coff ;; *-*bug) os=-coff ;; *-apple) os=-macos ;; *-atari*) os=-mint ;; *) os=-none ;; esac fi # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. vendor=unknown case $basic_machine in *-unknown) case $os in -riscix*) vendor=acorn ;; -sunos*) vendor=sun ;; -cnk*|-aix*) vendor=ibm ;; -beos*) vendor=be ;; -hpux*) vendor=hp ;; -mpeix*) vendor=hp ;; -hiux*) vendor=hitachi ;; -unos*) vendor=crds ;; -dgux*) vendor=dg ;; -luna*) vendor=omron ;; -genix*) vendor=ns ;; -mvs* | -opened*) vendor=ibm ;; -os400*) vendor=ibm ;; -ptx*) vendor=sequent ;; -tpf*) vendor=ibm ;; -vxsim* | -vxworks* | -windiss*) vendor=wrs ;; -aux*) vendor=apple ;; -hms*) vendor=hitachi ;; -mpw* | -macos*) vendor=apple ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) vendor=atari ;; -vos*) vendor=stratus ;; esac basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac echo $basic_machine$os exit # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: partclone-0.2.86/configure000077500000000000000000011425021262102574200155130ustar00rootroot00000000000000#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.69 for Partclone 0.2.86. # # Report bugs to . # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then _as_can_reexec=no; export _as_can_reexec; # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 as_fn_exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes else as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir/$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : CONFIG_SHELL=$as_shell as_have_required=yes if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : break 2 fi fi done;; esac as_found=false done $as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." if test x${ZSH_VERSION+set} = xset ; then $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org and thomas@nchc.org.tw $0: about your system, including any error possibly output $0: before this message. Then install a modern shell, or $0: manually run the script under such a shell if you do $0: have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall # in an infinite loop. This has already happened in practice. _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='Partclone' PACKAGE_TARNAME='partclone' PACKAGE_VERSION='0.2.86' PACKAGE_STRING='Partclone 0.2.86' PACKAGE_BUGREPORT='thomas@nchc.org.tw' PACKAGE_URL='' gt_needs= # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_STRING_H # if !defined STDC_HEADERS && defined HAVE_MEMORY_H # include # endif # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_subst_vars='am__EXEEXT_FALSE am__EXEEXT_TRUE LTLIBOBJS LIBOBJS ENABLE_FS_TEST_FALSE ENABLE_FS_TEST_TRUE ENABLE_MEMTRACE_FALSE ENABLE_MEMTRACE_TRUE ENABLE_TINFO_FALSE ENABLE_TINFO_TRUE ENABLE_STATIC_FALSE ENABLE_STATIC_TRUE ENABLE_NCURSESW_FALSE ENABLE_NCURSESW_TRUE ENABLE_MINIX_FALSE ENABLE_MINIX_TRUE ENABLE_BTRFS_FALSE ENABLE_BTRFS_TRUE ENABLE_JFS_FALSE ENABLE_JFS_TRUE ENABLE_VMFS_FALSE ENABLE_VMFS_TRUE ENABLE_UFS_FALSE ENABLE_UFS_TRUE NTFS_LIBS NTFS_CFLAGS ENABLE_NTFS_FALSE ENABLE_NTFS_TRUE ENABLE_NTFS_PROGS_FALSE ENABLE_NTFS_PROGS_TRUE ENABLE_NTFS_3G_FALSE ENABLE_NTFS_3G_TRUE ENABLE_NILFS2_FALSE ENABLE_NILFS2_TRUE ENABLE_F2FS_FALSE ENABLE_F2FS_TRUE ENABLE_EXFAT_FALSE ENABLE_EXFAT_TRUE ENABLE_FAT_FALSE ENABLE_FAT_TRUE ENABLE_HFSP_FALSE ENABLE_HFSP_TRUE ENABLE_REISER4_FALSE ENABLE_REISER4_TRUE ENABLE_REISERFS_FALSE ENABLE_REISERFS_TRUE ENABLE_XFS_FALSE ENABLE_XFS_TRUE EXT2FS_LIBS EXT2FS_CFLAGS EGREP GREP CPP ENABLE_EXTFS_FALSE ENABLE_EXTFS_TRUE UUID_LIBS UUID_CFLAGS PKG_CONFIG_LIBDIR PKG_CONFIG_PATH PKG_CONFIG ORIGINAL_CFLAGS ENABLE_ALL_FALSE ENABLE_ALL_TRUE LN_S RM POSUB LTLIBINTL LIBINTL INTLLIBS LTLIBICONV LIBICONV INTL_MACOSX_LIBS host_os host_vendor host_cpu host build_os build_vendor build_cpu build am__fastdepCC_FALSE am__fastdepCC_TRUE CCDEPMODE am__nodep AMDEPBACKSLASH AMDEP_FALSE AMDEP_TRUE am__quote am__include DEPDIR OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC MSGMERGE XGETTEXT_015 XGETTEXT GMSGFMT_015 MSGFMT_015 GMSGFMT MSGFMT USE_NLS AM_BACKSLASH AM_DEFAULT_VERBOSITY AM_DEFAULT_V AM_V am__untar am__tar AMTAR am__leading_dot SET_MAKE AWK mkdir_p MKDIR_P INSTALL_STRIP_PROGRAM STRIP install_sh MAKEINFO AUTOHEADER AUTOMAKE AUTOCONF ACLOCAL VERSION PACKAGE CYGPATH_W am__isrc INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir runstatedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking enable_silent_rules enable_nls enable_dependency_tracking with_gnu_ld enable_rpath with_libiconv_prefix with_libintl_prefix enable_largefile enable_all enable_extfs enable_xfs enable_reiserfs enable_reiser4 enable_hfsp enable_fat enable_exfat enable_f2fs enable_nilfs2 enable_ntfs enable_ufs enable_vmfs enable_jfs enable_btrfs enable_minix enable_ncursesw enable_static enable_mtrace enable_fs_test ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS PKG_CONFIG PKG_CONFIG_PATH PKG_CONFIG_LIBDIR UUID_CFLAGS UUID_LIBS CPP EXT2FS_CFLAGS EXT2FS_LIBS NTFS_CFLAGS NTFS_LIBS' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -runstatedir | --runstatedir | --runstatedi | --runstated \ | --runstate | --runstat | --runsta | --runst | --runs \ | --run | --ru | --r) ac_prev=runstatedir ;; -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ | --run=* | --ru=* | --r=*) runstatedir=$ac_optarg ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir runstatedir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures Partclone 0.2.86 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/partclone] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF Program names: --program-prefix=PREFIX prepend PREFIX to installed program names --program-suffix=SUFFIX append SUFFIX to installed program names --program-transform-name=PROGRAM run sed PROGRAM on installed program names System types: --build=BUILD configure for building on BUILD [guessed] --host=HOST cross-compile to build programs to run on HOST [BUILD] _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of Partclone 0.2.86:";; esac cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-silent-rules less verbose build output (undo: "make V=1") --disable-silent-rules verbose build output (undo: "make V=0") --disable-nls do not use Native Language Support --enable-dependency-tracking do not reject slow dependency extractors --disable-dependency-tracking speeds up one-time build --disable-rpath do not hardcode runtime library paths --disable-largefile omit support for large files --enable-all enable all supported file system --enable-extfs enable ext2/3/4 file system --enable-xfs enable XFS file system --enable-reiserfs enable REISERFS 3.6/3.6 file system --enable-reiser4 enable Reiser4 file system --enable-hfsp enable HFS plus file system --enable-fat enable FAT file system --enable-exfat enable EXFAT file system --enable-f2fs enable f2fs file system --enable-nilfs2 enable nilfs2 file system --enable-ntfs enable NTFS file system --enable-ufs enable UFS(1/2) file system --enable-vmfs enable vmfs file system --enable-jfs enable jfs file system --enable-btrfs enable btrfs file system --enable-minix enable minix file system --enable-ncursesw enable TEXT User Interface --enable-static enable static linking --enable-mtrace enable memory tracing --enable-fs-test enable file system clone/restore test Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-gnu-ld assume the C compiler uses GNU ld default=no --with-libiconv-prefix[=DIR] search for libiconv in DIR/include and DIR/lib --without-libiconv-prefix don't search for libiconv in includedir and libdir --with-libintl-prefix[=DIR] search for libintl in DIR/include and DIR/lib --without-libintl-prefix don't search for libintl in includedir and libdir Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory PKG_CONFIG path to pkg-config utility PKG_CONFIG_PATH directories to add to pkg-config's search path PKG_CONFIG_LIBDIR path overriding pkg-config's built-in search path UUID_CFLAGS C compiler flags for UUID, overriding pkg-config UUID_LIBS linker flags for UUID, overriding pkg-config CPP C preprocessor EXT2FS_CFLAGS C compiler flags for EXT2FS, overriding pkg-config EXT2FS_LIBS linker flags for EXT2FS, overriding pkg-config NTFS_CFLAGS C compiler flags for NTFS, overriding pkg-config NTFS_LIBS linker flags for NTFS, overriding pkg-config Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to . _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF Partclone configure 0.2.86 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_c_try_cpp LINENO # ---------------------- # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_cpp # ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists, giving a warning if it cannot be compiled using # the include files in INCLUDES and setting the cache variable VAR # accordingly. ac_fn_c_check_header_mongrel () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if eval \${$3+:} false; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } else # Is the header compilable? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 $as_echo_n "checking $2 usability... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_header_compiler=yes else ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 $as_echo "$ac_header_compiler" >&6; } # Is the header present? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 $as_echo_n "checking $2 presence... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <$2> _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : ac_header_preproc=yes else ac_header_preproc=no fi rm -f conftest.err conftest.i conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 $as_echo "$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( yes:no: ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 $as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; no:yes:* ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 $as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 $as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 $as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 $as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ( $as_echo "## --------------------------------- ## ## Report this to thomas@nchc.org.tw ## ## --------------------------------- ##" ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=\$ac_header_compiler" fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_mongrel # ac_fn_c_try_run LINENO # ---------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. Assumes # that executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then : ac_retval=0 else $as_echo "$as_me: program exited with status $ac_status" >&5 $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_run # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by Partclone $as_me 0.2.86, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo $as_echo "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo $as_echo "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then $as_echo "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then $as_echo "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h $as_echo "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_URL "$PACKAGE_URL" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then # We do not want a PATH search for config.site. case $CONFIG_SITE in #(( -*) ac_site_file1=./$CONFIG_SITE;; */*) ac_site_file1=$CONFIG_SITE;; *) ac_site_file1=./$CONFIG_SITE;; esac elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi gt_needs="$gt_needs " # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu am__api_version='1.15' ac_aux_dir= for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do if test -f "$ac_dir/install-sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f "$ac_dir/install.sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break elif test -f "$ac_dir/shtool"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/shtool install -c" break fi done if test -z "$ac_aux_dir"; then as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 $as_echo_n "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if ${ac_cv_path_install+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. # Account for people who put trailing slashes in PATH elements. case $as_dir/ in #(( ./ | .// | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else rm -rf conftest.one conftest.two conftest.dir echo one > conftest.one echo two > conftest.two mkdir conftest.dir if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi fi done done ;; esac done IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir fi if test "${ac_cv_path_install+set}" = set; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 $as_echo "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 $as_echo_n "checking whether build environment is sane... " >&6; } # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[\\\"\#\$\&\'\`$am_lf]*) as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;; esac case $srcdir in *[\\\"\#\$\&\'\`$am_lf\ \ ]*) as_fn_error $? "unsafe srcdir value: '$srcdir'" "$LINENO" 5;; esac # Do 'set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( am_has_slept=no for am_try in 1 2; do echo "timestamp, slept: $am_has_slept" > conftest.file set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$*" = "X"; then # -L didn't work. set X `ls -t "$srcdir/configure" conftest.file` fi if test "$*" != "X $srcdir/configure conftest.file" \ && test "$*" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". as_fn_error $? "ls -t appears to fail. Make sure there is not a broken alias in your environment" "$LINENO" 5 fi if test "$2" = conftest.file || test $am_try -eq 2; then break fi # Just in case. sleep 1 am_has_slept=yes done test "$2" = conftest.file ) then # Ok. : else as_fn_error $? "newly created file is older than distributed files! Check your system clock" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } # If we didn't sleep, we still need to ensure time stamps of config.status and # generated files are strictly newer. am_sleep_pid= if grep 'slept: no' conftest.file >/dev/null 2>&1; then ( sleep 1 ) & am_sleep_pid=$! fi rm -f conftest.file test "$program_prefix" != NONE && program_transform_name="s&^&$program_prefix&;$program_transform_name" # Use a double $ so make ignores it. test "$program_suffix" != NONE && program_transform_name="s&\$&$program_suffix&;$program_transform_name" # Double any \ or $. # By default was `s,x,x', remove it if useless. ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"` # Expand $ac_aux_dir to an absolute path. am_aux_dir=`cd "$ac_aux_dir" && pwd` if test x"${MISSING+set}" != xset; then case $am_aux_dir in *\ * | *\ *) MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; *) MISSING="\${SHELL} $am_aux_dir/missing" ;; esac fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then am_missing_run="$MISSING " else am_missing_run= { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5 $as_echo "$as_me: WARNING: 'missing' script is too old or missing" >&2;} fi if test x"${install_sh+set}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi # Installed binaries are usually stripped using 'strip' when the user # run "make install-strip". However 'strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the 'STRIP' environment variable to overrule this program. if test "$cross_compiling" != no; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. set dummy ${ac_tool_prefix}strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$STRIP"; then ac_cv_prog_STRIP="$STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 $as_echo "$STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_STRIP"; then ac_ct_STRIP=$STRIP # Extract the first word of "strip", so it can be a program name with args. set dummy strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_STRIP"; then ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_STRIP="strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 $as_echo "$ac_ct_STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac STRIP=$ac_ct_STRIP fi else STRIP="$ac_cv_prog_STRIP" fi fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5 $as_echo_n "checking for a thread-safe mkdir -p... " >&6; } if test -z "$MKDIR_P"; then if ${ac_cv_path_mkdir+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in mkdir gmkdir; do for ac_exec_ext in '' $ac_executable_extensions; do as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext" || continue case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( 'mkdir (GNU coreutils) '* | \ 'mkdir (coreutils) '* | \ 'mkdir (fileutils) '4.1*) ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext break 3;; esac done done done IFS=$as_save_IFS fi test -d ./--version && rmdir ./--version if test "${ac_cv_path_mkdir+set}" = set; then MKDIR_P="$ac_cv_path_mkdir -p" else # As a last resort, use the slow shell script. Don't cache a # value for MKDIR_P within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. MKDIR_P="$ac_install_sh -d" fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 $as_echo "$MKDIR_P" >&6; } for ac_prog in gawk mawk nawk awk do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_AWK+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AWK"; then ac_cv_prog_AWK="$AWK" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AWK="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AWK=$ac_cv_prog_AWK if test -n "$AWK"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 $as_echo "$AWK" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$AWK" && break done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 $as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } set x ${MAKE-make} ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then : $as_echo_n "(cached) " >&6 else cat >conftest.make <<\_ACEOF SHELL = /bin/sh all: @echo '@@@%%%=$(MAKE)=@@@%%%' _ACEOF # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. case `${MAKE-make} -f conftest.make 2>/dev/null` in *@@@%%%=?*=@@@%%%*) eval ac_cv_prog_make_${ac_make}_set=yes;; *) eval ac_cv_prog_make_${ac_make}_set=no;; esac rm -f conftest.make fi if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } SET_MAKE= else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } SET_MAKE="MAKE=${MAKE-make}" fi rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null # Check whether --enable-silent-rules was given. if test "${enable_silent_rules+set}" = set; then : enableval=$enable_silent_rules; fi case $enable_silent_rules in # ((( yes) AM_DEFAULT_VERBOSITY=0;; no) AM_DEFAULT_VERBOSITY=1;; *) AM_DEFAULT_VERBOSITY=1;; esac am_make=${MAKE-make} { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 $as_echo_n "checking whether $am_make supports nested variables... " >&6; } if ${am_cv_make_support_nested_variables+:} false; then : $as_echo_n "(cached) " >&6 else if $as_echo 'TRUE=$(BAR$(V)) BAR0=false BAR1=true V=1 am__doit: @$(TRUE) .PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then am_cv_make_support_nested_variables=yes else am_cv_make_support_nested_variables=no fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 $as_echo "$am_cv_make_support_nested_variables" >&6; } if test $am_cv_make_support_nested_variables = yes; then AM_V='$(V)' AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' else AM_V=$AM_DEFAULT_VERBOSITY AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY fi AM_BACKSLASH='\' if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." am__isrc=' -I$(srcdir)' # test to see if srcdir already configured if test -f $srcdir/config.status; then as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi # Define the identity of the package. PACKAGE='partclone' VERSION='0.2.86' cat >>confdefs.h <<_ACEOF #define PACKAGE "$PACKAGE" _ACEOF cat >>confdefs.h <<_ACEOF #define VERSION "$VERSION" _ACEOF # Some tools Automake needs. ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} # For better backward compatibility. To be removed once Automake 1.9.x # dies out for good. For more background, see: # # mkdir_p='$(MKDIR_P)' # We need awk for the "check" target (and possibly the TAP driver). The # system "awk" is bad on some platforms. # Always define AMTAR for backward compatibility. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AMTAR='$${TAR-tar}' # We'll loop over all known methods to create a tar archive until one works. _am_tools='gnutar pax cpio none' am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -' # POSIX will say in a future version that running "rm -f" with no argument # is OK; and we want to be able to make that assumption in our Makefile # recipes. So use an aggressive probe to check that the usage we want is # actually supported "in the wild" to an acceptable degree. # See automake bug#10828. # To make any issue more visible, cause the running configure to be aborted # by default if the 'rm' program in use doesn't match our expectations; the # user can still override this though. if rm -f && rm -fr && rm -rf; then : OK; else cat >&2 <<'END' Oops! Your 'rm' program seems unable to run without file operands specified on the command line, even when the '-f' option is present. This is contrary to the behaviour of most rm programs out there, and not conforming with the upcoming POSIX standard: Please tell bug-automake@gnu.org about your system, including the value of your $PATH and any error possibly output before this message. This can help us improve future automake versions. END if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then echo 'Configuration will proceed anyway, since you have set the' >&2 echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 echo >&2 else cat >&2 <<'END' Aborting the configuration process, to ensure you take notice of the issue. You can download and install GNU coreutils to get an 'rm' implementation that behaves properly: . If you want to complete the configuration process using your problematic 'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM to "yes", and re-run configure. END as_fn_error $? "Your 'rm' program is bad, sorry." "$LINENO" 5 fi fi mkdir_p="$MKDIR_P" case $mkdir_p in [\\/$]* | ?:[\\/]*) ;; */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether NLS is requested" >&5 $as_echo_n "checking whether NLS is requested... " >&6; } # Check whether --enable-nls was given. if test "${enable_nls+set}" = set; then : enableval=$enable_nls; USE_NLS=$enableval else USE_NLS=yes fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $USE_NLS" >&5 $as_echo "$USE_NLS" >&6; } # Prepare PATH_SEPARATOR. # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then echo "#! /bin/sh" >conf$$.sh echo "exit 0" >>conf$$.sh chmod +x conf$$.sh if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then PATH_SEPARATOR=';' else PATH_SEPARATOR=: fi rm -f conf$$.sh fi # Find out how to test for executable files. Don't use a zero-byte file, # as systems may use methods other than mode bits to determine executability. cat >conf$$.file <<_ASEOF #! /bin/sh exit 0 _ASEOF chmod +x conf$$.file if test -x conf$$.file >/dev/null 2>&1; then ac_executable_p="test -x" else ac_executable_p="test -f" fi rm -f conf$$.file # Extract the first word of "msgfmt", so it can be a program name with args. set dummy msgfmt; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_MSGFMT+:} false; then : $as_echo_n "(cached) " >&6 else case "$MSGFMT" in [\\/]* | ?:[\\/]*) ac_cv_path_MSGFMT="$MSGFMT" # Let the user override the test with a path. ;; *) ac_save_IFS="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS="$ac_save_IFS" test -z "$ac_dir" && ac_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $ac_executable_p "$ac_dir/$ac_word$ac_exec_ext"; then echo "$as_me: trying $ac_dir/$ac_word..." >&5 if $ac_dir/$ac_word --statistics /dev/null >&5 2>&1 && (if $ac_dir/$ac_word --statistics /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi); then ac_cv_path_MSGFMT="$ac_dir/$ac_word$ac_exec_ext" break 2 fi fi done done IFS="$ac_save_IFS" test -z "$ac_cv_path_MSGFMT" && ac_cv_path_MSGFMT=":" ;; esac fi MSGFMT="$ac_cv_path_MSGFMT" if test "$MSGFMT" != ":"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MSGFMT" >&5 $as_echo "$MSGFMT" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "gmsgfmt", so it can be a program name with args. set dummy gmsgfmt; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_GMSGFMT+:} false; then : $as_echo_n "(cached) " >&6 else case $GMSGFMT in [\\/]* | ?:[\\/]*) ac_cv_path_GMSGFMT="$GMSGFMT" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_GMSGFMT="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_path_GMSGFMT" && ac_cv_path_GMSGFMT="$MSGFMT" ;; esac fi GMSGFMT=$ac_cv_path_GMSGFMT if test -n "$GMSGFMT"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GMSGFMT" >&5 $as_echo "$GMSGFMT" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi case `$MSGFMT --version | sed 1q | sed -e 's,^[^0-9]*,,'` in '' | 0.[0-9] | 0.[0-9].* | 0.1[0-4] | 0.1[0-4].*) MSGFMT_015=: ;; *) MSGFMT_015=$MSGFMT ;; esac case `$GMSGFMT --version | sed 1q | sed -e 's,^[^0-9]*,,'` in '' | 0.[0-9] | 0.[0-9].* | 0.1[0-4] | 0.1[0-4].*) GMSGFMT_015=: ;; *) GMSGFMT_015=$GMSGFMT ;; esac # Prepare PATH_SEPARATOR. # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then echo "#! /bin/sh" >conf$$.sh echo "exit 0" >>conf$$.sh chmod +x conf$$.sh if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then PATH_SEPARATOR=';' else PATH_SEPARATOR=: fi rm -f conf$$.sh fi # Find out how to test for executable files. Don't use a zero-byte file, # as systems may use methods other than mode bits to determine executability. cat >conf$$.file <<_ASEOF #! /bin/sh exit 0 _ASEOF chmod +x conf$$.file if test -x conf$$.file >/dev/null 2>&1; then ac_executable_p="test -x" else ac_executable_p="test -f" fi rm -f conf$$.file # Extract the first word of "xgettext", so it can be a program name with args. set dummy xgettext; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_XGETTEXT+:} false; then : $as_echo_n "(cached) " >&6 else case "$XGETTEXT" in [\\/]* | ?:[\\/]*) ac_cv_path_XGETTEXT="$XGETTEXT" # Let the user override the test with a path. ;; *) ac_save_IFS="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS="$ac_save_IFS" test -z "$ac_dir" && ac_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $ac_executable_p "$ac_dir/$ac_word$ac_exec_ext"; then echo "$as_me: trying $ac_dir/$ac_word..." >&5 if $ac_dir/$ac_word --omit-header --copyright-holder= --msgid-bugs-address= /dev/null >&5 2>&1 && (if $ac_dir/$ac_word --omit-header --copyright-holder= --msgid-bugs-address= /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi); then ac_cv_path_XGETTEXT="$ac_dir/$ac_word$ac_exec_ext" break 2 fi fi done done IFS="$ac_save_IFS" test -z "$ac_cv_path_XGETTEXT" && ac_cv_path_XGETTEXT=":" ;; esac fi XGETTEXT="$ac_cv_path_XGETTEXT" if test "$XGETTEXT" != ":"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $XGETTEXT" >&5 $as_echo "$XGETTEXT" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f messages.po case `$XGETTEXT --version | sed 1q | sed -e 's,^[^0-9]*,,'` in '' | 0.[0-9] | 0.[0-9].* | 0.1[0-4] | 0.1[0-4].*) XGETTEXT_015=: ;; *) XGETTEXT_015=$XGETTEXT ;; esac # Prepare PATH_SEPARATOR. # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then echo "#! /bin/sh" >conf$$.sh echo "exit 0" >>conf$$.sh chmod +x conf$$.sh if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then PATH_SEPARATOR=';' else PATH_SEPARATOR=: fi rm -f conf$$.sh fi # Find out how to test for executable files. Don't use a zero-byte file, # as systems may use methods other than mode bits to determine executability. cat >conf$$.file <<_ASEOF #! /bin/sh exit 0 _ASEOF chmod +x conf$$.file if test -x conf$$.file >/dev/null 2>&1; then ac_executable_p="test -x" else ac_executable_p="test -f" fi rm -f conf$$.file # Extract the first word of "msgmerge", so it can be a program name with args. set dummy msgmerge; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_MSGMERGE+:} false; then : $as_echo_n "(cached) " >&6 else case "$MSGMERGE" in [\\/]* | ?:[\\/]*) ac_cv_path_MSGMERGE="$MSGMERGE" # Let the user override the test with a path. ;; *) ac_save_IFS="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS="$ac_save_IFS" test -z "$ac_dir" && ac_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $ac_executable_p "$ac_dir/$ac_word$ac_exec_ext"; then echo "$as_me: trying $ac_dir/$ac_word..." >&5 if $ac_dir/$ac_word --update -q /dev/null /dev/null >&5 2>&1; then ac_cv_path_MSGMERGE="$ac_dir/$ac_word$ac_exec_ext" break 2 fi fi done done IFS="$ac_save_IFS" test -z "$ac_cv_path_MSGMERGE" && ac_cv_path_MSGMERGE=":" ;; esac fi MSGMERGE="$ac_cv_path_MSGMERGE" if test "$MSGMERGE" != ":"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MSGMERGE" >&5 $as_echo "$MSGMERGE" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$localedir" || localedir='${datadir}/locale' ac_config_commands="$ac_config_commands po-directories" if test "X$prefix" = "XNONE"; then acl_final_prefix="$ac_default_prefix" else acl_final_prefix="$prefix" fi if test "X$exec_prefix" = "XNONE"; then acl_final_exec_prefix='${prefix}' else acl_final_exec_prefix="$exec_prefix" fi acl_save_prefix="$prefix" prefix="$acl_final_prefix" eval acl_final_exec_prefix=\"$acl_final_exec_prefix\" prefix="$acl_save_prefix" DEPDIR="${am__leading_dot}deps" ac_config_commands="$ac_config_commands depfiles" am_make=${MAKE-make} cat > confinc << 'END' am__doit: @echo this is the am__doit target .PHONY: am__doit END # If we don't find an include directive, just comment out the code. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5 $as_echo_n "checking for style of include used by $am_make... " >&6; } am__include="#" am__quote= _am_result=none # First try GNU make style include. echo "include confinc" > confmf # Ignore all kinds of additional output from 'make'. case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=include am__quote= _am_result=GNU ;; esac # Now try BSD make style include. if test "$am__include" = "#"; then echo '.include "confinc"' > confmf case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=.include am__quote="\"" _am_result=BSD ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5 $as_echo "$_am_result" >&6; } rm -f confinc confmf # Check whether --enable-dependency-tracking was given. if test "${enable_dependency_tracking+set}" = set; then : enableval=$enable_dependency_tracking; fi if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' am__nodep='_no' fi if test "x$enable_dependency_tracking" != xno; then AMDEP_TRUE= AMDEP_FALSE='#' else AMDEP_TRUE='#' AMDEP_FALSE= fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 $as_echo_n "checking whether the C compiler works... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi if test -z "$ac_file"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 $as_echo_n "checking for C compiler default output file name... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 $as_echo "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } if ${ac_cv_objext+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5 $as_echo_n "checking whether $CC understands -c and -o together... " >&6; } if ${am_cv_prog_cc_c_o+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF # Make sure it works both with $CC and with simple cc. # Following AC_PROG_CC_C_O, we do the test twice because some # compilers refuse to overwrite an existing .o file with -o, # though they will create one. am_cv_prog_cc_c_o=yes for am_i in 1 2; do if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5 ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } \ && test -f conftest2.$ac_objext; then : OK else am_cv_prog_cc_c_o=no break fi done rm -f core conftest* unset am_i fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5 $as_echo "$am_cv_prog_cc_c_o" >&6; } if test "$am_cv_prog_cc_c_o" != yes; then # Losing compiler, so override with the script. # FIXME: It is wrong to rewrite CC. # But if we don't then we get into trouble of one sort or another. # A longer-term fix would be to have automake use am__CC in this case, # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" CC="$am_aux_dir/compile $CC" fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu depcc="$CC" am_compiler_list= { $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 $as_echo_n "checking dependency style of $depcc... " >&6; } if ${am_cv_CC_dependencies_compiler_type+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named 'D' -- because '-MD' means "put the output # in D". rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_CC_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` fi am__universal=false case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with '-c' and '-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle '-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # After this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested. if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_CC_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_CC_dependencies_compiler_type=none fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 $as_echo "$am_cv_CC_dependencies_compiler_type" >&6; } CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type if test "x$enable_dependency_tracking" != xno \ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then am__fastdepCC_TRUE= am__fastdepCC_FALSE='#' else am__fastdepCC_TRUE='#' am__fastdepCC_FALSE= fi # Make sure we can run config.sub. $SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 $as_echo_n "checking build system type... " >&6; } if ${ac_cv_build+:} false; then : $as_echo_n "(cached) " >&6 else ac_build_alias=$build_alias test "x$ac_build_alias" = x && ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` test "x$ac_build_alias" = x && as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 $as_echo "$ac_cv_build" >&6; } case $ac_cv_build in *-*-*) ;; *) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; esac build=$ac_cv_build ac_save_IFS=$IFS; IFS='-' set x $ac_cv_build shift build_cpu=$1 build_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: build_os=$* IFS=$ac_save_IFS case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 $as_echo_n "checking host system type... " >&6; } if ${ac_cv_host+:} false; then : $as_echo_n "(cached) " >&6 else if test "x$host_alias" = x; then ac_cv_host=$ac_cv_build else ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 $as_echo "$ac_cv_host" >&6; } case $ac_cv_host in *-*-*) ;; *) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; esac host=$ac_cv_host ac_save_IFS=$IFS; IFS='-' set x $ac_cv_host shift host_cpu=$1 host_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: host_os=$* IFS=$ac_save_IFS case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac # Check whether --with-gnu-ld was given. if test "${with_gnu_ld+set}" = set; then : withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes else with_gnu_ld=no fi # Prepare PATH_SEPARATOR. # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then echo "#! /bin/sh" >conf$$.sh echo "exit 0" >>conf$$.sh chmod +x conf$$.sh if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then PATH_SEPARATOR=';' else PATH_SEPARATOR=: fi rm -f conf$$.sh fi ac_prog=ld if test "$GCC" = yes; then # Check if gcc -print-prog-name=ld gives a path. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by GCC" >&5 $as_echo_n "checking for ld used by GCC... " >&6; } case $host in *-*-mingw*) # gcc leaves a trailing carriage return which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case $ac_prog in # Accept absolute paths. [\\/]* | [A-Za-z]:[\\/]*) re_direlt='/[^/][^/]*/\.\./' # Canonicalize the path of ld ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'` while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"` done test -z "$LD" && LD="$ac_prog" ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test "$with_gnu_ld" = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 $as_echo_n "checking for GNU ld... " >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 $as_echo_n "checking for non-GNU ld... " >&6; } fi if ${acl_cv_path_LD+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$LD"; then IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}" for ac_dir in $PATH; do test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then acl_cv_path_LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some GNU ld's only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$acl_cv_path_LD" -v 2>&1 < /dev/null` in *GNU* | *'with BFD'*) test "$with_gnu_ld" != no && break ;; *) test "$with_gnu_ld" != yes && break ;; esac fi done IFS="$ac_save_ifs" else acl_cv_path_LD="$LD" # Let the user override the test with a path. fi fi LD="$acl_cv_path_LD" if test -n "$LD"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5 $as_echo "$LD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 $as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } if ${acl_cv_prog_gnu_ld+:} false; then : $as_echo_n "(cached) " >&6 else # I'd rather use --version here, but apparently some GNU ld's only accept -v. case `$LD -v 2>&1 &5 $as_echo "$acl_cv_prog_gnu_ld" >&6; } with_gnu_ld=$acl_cv_prog_gnu_ld { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shared library run path origin" >&5 $as_echo_n "checking for shared library run path origin... " >&6; } if ${acl_cv_rpath+:} false; then : $as_echo_n "(cached) " >&6 else CC="$CC" GCC="$GCC" LDFLAGS="$LDFLAGS" LD="$LD" with_gnu_ld="$with_gnu_ld" \ ${CONFIG_SHELL-/bin/sh} "$ac_aux_dir/config.rpath" "$host" > conftest.sh . ./conftest.sh rm -f ./conftest.sh acl_cv_rpath=done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $acl_cv_rpath" >&5 $as_echo "$acl_cv_rpath" >&6; } wl="$acl_cv_wl" libext="$acl_cv_libext" shlibext="$acl_cv_shlibext" hardcode_libdir_flag_spec="$acl_cv_hardcode_libdir_flag_spec" hardcode_libdir_separator="$acl_cv_hardcode_libdir_separator" hardcode_direct="$acl_cv_hardcode_direct" hardcode_minus_L="$acl_cv_hardcode_minus_L" # Check whether --enable-rpath was given. if test "${enable_rpath+set}" = set; then : enableval=$enable_rpath; : else enable_rpath=yes fi acl_libdirstem=lib searchpath=`(LC_ALL=C $CC -print-search-dirs) 2>/dev/null | sed -n -e 's,^libraries: ,,p' | sed -e 's,^=,,'` if test -n "$searchpath"; then acl_save_IFS="${IFS= }"; IFS=":" for searchdir in $searchpath; do if test -d "$searchdir"; then case "$searchdir" in */lib64/ | */lib64 ) acl_libdirstem=lib64 ;; *) searchdir=`cd "$searchdir" && pwd` case "$searchdir" in */lib64 ) acl_libdirstem=lib64 ;; esac ;; esac fi done IFS="$acl_save_IFS" fi use_additional=yes acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" eval additional_includedir=\"$includedir\" eval additional_libdir=\"$libdir\" exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" # Check whether --with-libiconv-prefix was given. if test "${with_libiconv_prefix+set}" = set; then : withval=$with_libiconv_prefix; if test "X$withval" = "Xno"; then use_additional=no else if test "X$withval" = "X"; then acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" eval additional_includedir=\"$includedir\" eval additional_libdir=\"$libdir\" exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" else additional_includedir="$withval/include" additional_libdir="$withval/$acl_libdirstem" fi fi fi LIBICONV= LTLIBICONV= INCICONV= rpathdirs= ltrpathdirs= names_already_handled= names_next_round='iconv ' while test -n "$names_next_round"; do names_this_round="$names_next_round" names_next_round= for name in $names_this_round; do already_handled= for n in $names_already_handled; do if test "$n" = "$name"; then already_handled=yes break fi done if test -z "$already_handled"; then names_already_handled="$names_already_handled $name" uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./-|ABCDEFGHIJKLMNOPQRSTUVWXYZ___|'` eval value=\"\$HAVE_LIB$uppername\" if test -n "$value"; then if test "$value" = yes; then eval value=\"\$LIB$uppername\" test -z "$value" || LIBICONV="${LIBICONV}${LIBICONV:+ }$value" eval value=\"\$LTLIB$uppername\" test -z "$value" || LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }$value" else : fi else found_dir= found_la= found_so= found_a= if test $use_additional = yes; then if test -n "$shlibext" \ && { test -f "$additional_libdir/lib$name.$shlibext" \ || { test "$shlibext" = dll \ && test -f "$additional_libdir/lib$name.dll.a"; }; }; then found_dir="$additional_libdir" if test -f "$additional_libdir/lib$name.$shlibext"; then found_so="$additional_libdir/lib$name.$shlibext" else found_so="$additional_libdir/lib$name.dll.a" fi if test -f "$additional_libdir/lib$name.la"; then found_la="$additional_libdir/lib$name.la" fi else if test -f "$additional_libdir/lib$name.$libext"; then found_dir="$additional_libdir" found_a="$additional_libdir/lib$name.$libext" if test -f "$additional_libdir/lib$name.la"; then found_la="$additional_libdir/lib$name.la" fi fi fi fi if test "X$found_dir" = "X"; then for x in $LDFLAGS $LTLIBICONV; do acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" eval x=\"$x\" exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" case "$x" in -L*) dir=`echo "X$x" | sed -e 's/^X-L//'` if test -n "$shlibext" \ && { test -f "$dir/lib$name.$shlibext" \ || { test "$shlibext" = dll \ && test -f "$dir/lib$name.dll.a"; }; }; then found_dir="$dir" if test -f "$dir/lib$name.$shlibext"; then found_so="$dir/lib$name.$shlibext" else found_so="$dir/lib$name.dll.a" fi if test -f "$dir/lib$name.la"; then found_la="$dir/lib$name.la" fi else if test -f "$dir/lib$name.$libext"; then found_dir="$dir" found_a="$dir/lib$name.$libext" if test -f "$dir/lib$name.la"; then found_la="$dir/lib$name.la" fi fi fi ;; esac if test "X$found_dir" != "X"; then break fi done fi if test "X$found_dir" != "X"; then LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }-L$found_dir -l$name" if test "X$found_so" != "X"; then if test "$enable_rpath" = no || test "X$found_dir" = "X/usr/$acl_libdirstem"; then LIBICONV="${LIBICONV}${LIBICONV:+ }$found_so" else haveit= for x in $ltrpathdirs; do if test "X$x" = "X$found_dir"; then haveit=yes break fi done if test -z "$haveit"; then ltrpathdirs="$ltrpathdirs $found_dir" fi if test "$hardcode_direct" = yes; then LIBICONV="${LIBICONV}${LIBICONV:+ }$found_so" else if test -n "$hardcode_libdir_flag_spec" && test "$hardcode_minus_L" = no; then LIBICONV="${LIBICONV}${LIBICONV:+ }$found_so" haveit= for x in $rpathdirs; do if test "X$x" = "X$found_dir"; then haveit=yes break fi done if test -z "$haveit"; then rpathdirs="$rpathdirs $found_dir" fi else haveit= for x in $LDFLAGS $LIBICONV; do acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" eval x=\"$x\" exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" if test "X$x" = "X-L$found_dir"; then haveit=yes break fi done if test -z "$haveit"; then LIBICONV="${LIBICONV}${LIBICONV:+ }-L$found_dir" fi if test "$hardcode_minus_L" != no; then LIBICONV="${LIBICONV}${LIBICONV:+ }$found_so" else LIBICONV="${LIBICONV}${LIBICONV:+ }-l$name" fi fi fi fi else if test "X$found_a" != "X"; then LIBICONV="${LIBICONV}${LIBICONV:+ }$found_a" else LIBICONV="${LIBICONV}${LIBICONV:+ }-L$found_dir -l$name" fi fi additional_includedir= case "$found_dir" in */$acl_libdirstem | */$acl_libdirstem/) basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem/"'*$,,'` additional_includedir="$basedir/include" ;; esac if test "X$additional_includedir" != "X"; then if test "X$additional_includedir" != "X/usr/include"; then haveit= if test "X$additional_includedir" = "X/usr/local/include"; then if test -n "$GCC"; then case $host_os in linux* | gnu* | k*bsd*-gnu) haveit=yes;; esac fi fi if test -z "$haveit"; then for x in $CPPFLAGS $INCICONV; do acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" eval x=\"$x\" exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" if test "X$x" = "X-I$additional_includedir"; then haveit=yes break fi done if test -z "$haveit"; then if test -d "$additional_includedir"; then INCICONV="${INCICONV}${INCICONV:+ }-I$additional_includedir" fi fi fi fi fi if test -n "$found_la"; then save_libdir="$libdir" case "$found_la" in */* | *\\*) . "$found_la" ;; *) . "./$found_la" ;; esac libdir="$save_libdir" for dep in $dependency_libs; do case "$dep" in -L*) additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'` if test "X$additional_libdir" != "X/usr/$acl_libdirstem"; then haveit= if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem"; then if test -n "$GCC"; then case $host_os in linux* | gnu* | k*bsd*-gnu) haveit=yes;; esac fi fi if test -z "$haveit"; then haveit= for x in $LDFLAGS $LIBICONV; do acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" eval x=\"$x\" exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" if test "X$x" = "X-L$additional_libdir"; then haveit=yes break fi done if test -z "$haveit"; then if test -d "$additional_libdir"; then LIBICONV="${LIBICONV}${LIBICONV:+ }-L$additional_libdir" fi fi haveit= for x in $LDFLAGS $LTLIBICONV; do acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" eval x=\"$x\" exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" if test "X$x" = "X-L$additional_libdir"; then haveit=yes break fi done if test -z "$haveit"; then if test -d "$additional_libdir"; then LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }-L$additional_libdir" fi fi fi fi ;; -R*) dir=`echo "X$dep" | sed -e 's/^X-R//'` if test "$enable_rpath" != no; then haveit= for x in $rpathdirs; do if test "X$x" = "X$dir"; then haveit=yes break fi done if test -z "$haveit"; then rpathdirs="$rpathdirs $dir" fi haveit= for x in $ltrpathdirs; do if test "X$x" = "X$dir"; then haveit=yes break fi done if test -z "$haveit"; then ltrpathdirs="$ltrpathdirs $dir" fi fi ;; -l*) names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'` ;; *.la) names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'` ;; *) LIBICONV="${LIBICONV}${LIBICONV:+ }$dep" LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }$dep" ;; esac done fi else LIBICONV="${LIBICONV}${LIBICONV:+ }-l$name" LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }-l$name" fi fi fi done done if test "X$rpathdirs" != "X"; then if test -n "$hardcode_libdir_separator"; then alldirs= for found_dir in $rpathdirs; do alldirs="${alldirs}${alldirs:+$hardcode_libdir_separator}$found_dir" done acl_save_libdir="$libdir" libdir="$alldirs" eval flag=\"$hardcode_libdir_flag_spec\" libdir="$acl_save_libdir" LIBICONV="${LIBICONV}${LIBICONV:+ }$flag" else for found_dir in $rpathdirs; do acl_save_libdir="$libdir" libdir="$found_dir" eval flag=\"$hardcode_libdir_flag_spec\" libdir="$acl_save_libdir" LIBICONV="${LIBICONV}${LIBICONV:+ }$flag" done fi fi if test "X$ltrpathdirs" != "X"; then for found_dir in $ltrpathdirs; do LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }-R$found_dir" done fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for CFPreferencesCopyAppValue" >&5 $as_echo_n "checking for CFPreferencesCopyAppValue... " >&6; } if ${gt_cv_func_CFPreferencesCopyAppValue+:} false; then : $as_echo_n "(cached) " >&6 else gt_save_LIBS="$LIBS" LIBS="$LIBS -Wl,-framework -Wl,CoreFoundation" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { CFPreferencesCopyAppValue(NULL, NULL) ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : gt_cv_func_CFPreferencesCopyAppValue=yes else gt_cv_func_CFPreferencesCopyAppValue=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS="$gt_save_LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gt_cv_func_CFPreferencesCopyAppValue" >&5 $as_echo "$gt_cv_func_CFPreferencesCopyAppValue" >&6; } if test $gt_cv_func_CFPreferencesCopyAppValue = yes; then $as_echo "#define HAVE_CFPREFERENCESCOPYAPPVALUE 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for CFLocaleCopyCurrent" >&5 $as_echo_n "checking for CFLocaleCopyCurrent... " >&6; } if ${gt_cv_func_CFLocaleCopyCurrent+:} false; then : $as_echo_n "(cached) " >&6 else gt_save_LIBS="$LIBS" LIBS="$LIBS -Wl,-framework -Wl,CoreFoundation" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { CFLocaleCopyCurrent(); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : gt_cv_func_CFLocaleCopyCurrent=yes else gt_cv_func_CFLocaleCopyCurrent=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS="$gt_save_LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gt_cv_func_CFLocaleCopyCurrent" >&5 $as_echo "$gt_cv_func_CFLocaleCopyCurrent" >&6; } if test $gt_cv_func_CFLocaleCopyCurrent = yes; then $as_echo "#define HAVE_CFLOCALECOPYCURRENT 1" >>confdefs.h fi INTL_MACOSX_LIBS= if test $gt_cv_func_CFPreferencesCopyAppValue = yes || test $gt_cv_func_CFLocaleCopyCurrent = yes; then INTL_MACOSX_LIBS="-Wl,-framework -Wl,CoreFoundation" fi LIBINTL= LTLIBINTL= POSUB= case " $gt_needs " in *" need-formatstring-macros "*) gt_api_version=3 ;; *" need-ngettext "*) gt_api_version=2 ;; *) gt_api_version=1 ;; esac gt_func_gnugettext_libc="gt_cv_func_gnugettext${gt_api_version}_libc" gt_func_gnugettext_libintl="gt_cv_func_gnugettext${gt_api_version}_libintl" if test "$USE_NLS" = "yes"; then gt_use_preinstalled_gnugettext=no if test $gt_api_version -ge 3; then gt_revision_test_code=' #ifndef __GNU_GETTEXT_SUPPORTED_REVISION #define __GNU_GETTEXT_SUPPORTED_REVISION(major) ((major) == 0 ? 0 : -1) #endif typedef int array [2 * (__GNU_GETTEXT_SUPPORTED_REVISION(0) >= 1) - 1]; ' else gt_revision_test_code= fi if test $gt_api_version -ge 2; then gt_expression_test_code=' + * ngettext ("", "", 0)' else gt_expression_test_code= fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU gettext in libc" >&5 $as_echo_n "checking for GNU gettext in libc... " >&6; } if eval \${$gt_func_gnugettext_libc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include $gt_revision_test_code extern int _nl_msg_cat_cntr; extern int *_nl_domain_bindings; int main () { bindtextdomain ("", ""); return * gettext ("")$gt_expression_test_code + _nl_msg_cat_cntr + *_nl_domain_bindings ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : eval "$gt_func_gnugettext_libc=yes" else eval "$gt_func_gnugettext_libc=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$gt_func_gnugettext_libc { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } if { eval "gt_val=\$$gt_func_gnugettext_libc"; test "$gt_val" != "yes"; }; then am_save_CPPFLAGS="$CPPFLAGS" for element in $INCICONV; do haveit= for x in $CPPFLAGS; do acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" eval x=\"$x\" exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" if test "X$x" = "X$element"; then haveit=yes break fi done if test -z "$haveit"; then CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }$element" fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for iconv" >&5 $as_echo_n "checking for iconv... " >&6; } if ${am_cv_func_iconv+:} false; then : $as_echo_n "(cached) " >&6 else am_cv_func_iconv="no, consider installing GNU libiconv" am_cv_lib_iconv=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { iconv_t cd = iconv_open("",""); iconv(cd,NULL,NULL,NULL,NULL); iconv_close(cd); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : am_cv_func_iconv=yes fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test "$am_cv_func_iconv" != yes; then am_save_LIBS="$LIBS" LIBS="$LIBS $LIBICONV" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { iconv_t cd = iconv_open("",""); iconv(cd,NULL,NULL,NULL,NULL); iconv_close(cd); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : am_cv_lib_iconv=yes am_cv_func_iconv=yes fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS="$am_save_LIBS" fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_func_iconv" >&5 $as_echo "$am_cv_func_iconv" >&6; } if test "$am_cv_func_iconv" = yes; then $as_echo "#define HAVE_ICONV 1" >>confdefs.h fi if test "$am_cv_lib_iconv" = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to link with libiconv" >&5 $as_echo_n "checking how to link with libiconv... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIBICONV" >&5 $as_echo "$LIBICONV" >&6; } else CPPFLAGS="$am_save_CPPFLAGS" LIBICONV= LTLIBICONV= fi use_additional=yes acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" eval additional_includedir=\"$includedir\" eval additional_libdir=\"$libdir\" exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" # Check whether --with-libintl-prefix was given. if test "${with_libintl_prefix+set}" = set; then : withval=$with_libintl_prefix; if test "X$withval" = "Xno"; then use_additional=no else if test "X$withval" = "X"; then acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" eval additional_includedir=\"$includedir\" eval additional_libdir=\"$libdir\" exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" else additional_includedir="$withval/include" additional_libdir="$withval/$acl_libdirstem" fi fi fi LIBINTL= LTLIBINTL= INCINTL= rpathdirs= ltrpathdirs= names_already_handled= names_next_round='intl ' while test -n "$names_next_round"; do names_this_round="$names_next_round" names_next_round= for name in $names_this_round; do already_handled= for n in $names_already_handled; do if test "$n" = "$name"; then already_handled=yes break fi done if test -z "$already_handled"; then names_already_handled="$names_already_handled $name" uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./-|ABCDEFGHIJKLMNOPQRSTUVWXYZ___|'` eval value=\"\$HAVE_LIB$uppername\" if test -n "$value"; then if test "$value" = yes; then eval value=\"\$LIB$uppername\" test -z "$value" || LIBINTL="${LIBINTL}${LIBINTL:+ }$value" eval value=\"\$LTLIB$uppername\" test -z "$value" || LTLIBINTL="${LTLIBINTL}${LTLIBINTL:+ }$value" else : fi else found_dir= found_la= found_so= found_a= if test $use_additional = yes; then if test -n "$shlibext" \ && { test -f "$additional_libdir/lib$name.$shlibext" \ || { test "$shlibext" = dll \ && test -f "$additional_libdir/lib$name.dll.a"; }; }; then found_dir="$additional_libdir" if test -f "$additional_libdir/lib$name.$shlibext"; then found_so="$additional_libdir/lib$name.$shlibext" else found_so="$additional_libdir/lib$name.dll.a" fi if test -f "$additional_libdir/lib$name.la"; then found_la="$additional_libdir/lib$name.la" fi else if test -f "$additional_libdir/lib$name.$libext"; then found_dir="$additional_libdir" found_a="$additional_libdir/lib$name.$libext" if test -f "$additional_libdir/lib$name.la"; then found_la="$additional_libdir/lib$name.la" fi fi fi fi if test "X$found_dir" = "X"; then for x in $LDFLAGS $LTLIBINTL; do acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" eval x=\"$x\" exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" case "$x" in -L*) dir=`echo "X$x" | sed -e 's/^X-L//'` if test -n "$shlibext" \ && { test -f "$dir/lib$name.$shlibext" \ || { test "$shlibext" = dll \ && test -f "$dir/lib$name.dll.a"; }; }; then found_dir="$dir" if test -f "$dir/lib$name.$shlibext"; then found_so="$dir/lib$name.$shlibext" else found_so="$dir/lib$name.dll.a" fi if test -f "$dir/lib$name.la"; then found_la="$dir/lib$name.la" fi else if test -f "$dir/lib$name.$libext"; then found_dir="$dir" found_a="$dir/lib$name.$libext" if test -f "$dir/lib$name.la"; then found_la="$dir/lib$name.la" fi fi fi ;; esac if test "X$found_dir" != "X"; then break fi done fi if test "X$found_dir" != "X"; then LTLIBINTL="${LTLIBINTL}${LTLIBINTL:+ }-L$found_dir -l$name" if test "X$found_so" != "X"; then if test "$enable_rpath" = no || test "X$found_dir" = "X/usr/$acl_libdirstem"; then LIBINTL="${LIBINTL}${LIBINTL:+ }$found_so" else haveit= for x in $ltrpathdirs; do if test "X$x" = "X$found_dir"; then haveit=yes break fi done if test -z "$haveit"; then ltrpathdirs="$ltrpathdirs $found_dir" fi if test "$hardcode_direct" = yes; then LIBINTL="${LIBINTL}${LIBINTL:+ }$found_so" else if test -n "$hardcode_libdir_flag_spec" && test "$hardcode_minus_L" = no; then LIBINTL="${LIBINTL}${LIBINTL:+ }$found_so" haveit= for x in $rpathdirs; do if test "X$x" = "X$found_dir"; then haveit=yes break fi done if test -z "$haveit"; then rpathdirs="$rpathdirs $found_dir" fi else haveit= for x in $LDFLAGS $LIBINTL; do acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" eval x=\"$x\" exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" if test "X$x" = "X-L$found_dir"; then haveit=yes break fi done if test -z "$haveit"; then LIBINTL="${LIBINTL}${LIBINTL:+ }-L$found_dir" fi if test "$hardcode_minus_L" != no; then LIBINTL="${LIBINTL}${LIBINTL:+ }$found_so" else LIBINTL="${LIBINTL}${LIBINTL:+ }-l$name" fi fi fi fi else if test "X$found_a" != "X"; then LIBINTL="${LIBINTL}${LIBINTL:+ }$found_a" else LIBINTL="${LIBINTL}${LIBINTL:+ }-L$found_dir -l$name" fi fi additional_includedir= case "$found_dir" in */$acl_libdirstem | */$acl_libdirstem/) basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem/"'*$,,'` additional_includedir="$basedir/include" ;; esac if test "X$additional_includedir" != "X"; then if test "X$additional_includedir" != "X/usr/include"; then haveit= if test "X$additional_includedir" = "X/usr/local/include"; then if test -n "$GCC"; then case $host_os in linux* | gnu* | k*bsd*-gnu) haveit=yes;; esac fi fi if test -z "$haveit"; then for x in $CPPFLAGS $INCINTL; do acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" eval x=\"$x\" exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" if test "X$x" = "X-I$additional_includedir"; then haveit=yes break fi done if test -z "$haveit"; then if test -d "$additional_includedir"; then INCINTL="${INCINTL}${INCINTL:+ }-I$additional_includedir" fi fi fi fi fi if test -n "$found_la"; then save_libdir="$libdir" case "$found_la" in */* | *\\*) . "$found_la" ;; *) . "./$found_la" ;; esac libdir="$save_libdir" for dep in $dependency_libs; do case "$dep" in -L*) additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'` if test "X$additional_libdir" != "X/usr/$acl_libdirstem"; then haveit= if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem"; then if test -n "$GCC"; then case $host_os in linux* | gnu* | k*bsd*-gnu) haveit=yes;; esac fi fi if test -z "$haveit"; then haveit= for x in $LDFLAGS $LIBINTL; do acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" eval x=\"$x\" exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" if test "X$x" = "X-L$additional_libdir"; then haveit=yes break fi done if test -z "$haveit"; then if test -d "$additional_libdir"; then LIBINTL="${LIBINTL}${LIBINTL:+ }-L$additional_libdir" fi fi haveit= for x in $LDFLAGS $LTLIBINTL; do acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" eval x=\"$x\" exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" if test "X$x" = "X-L$additional_libdir"; then haveit=yes break fi done if test -z "$haveit"; then if test -d "$additional_libdir"; then LTLIBINTL="${LTLIBINTL}${LTLIBINTL:+ }-L$additional_libdir" fi fi fi fi ;; -R*) dir=`echo "X$dep" | sed -e 's/^X-R//'` if test "$enable_rpath" != no; then haveit= for x in $rpathdirs; do if test "X$x" = "X$dir"; then haveit=yes break fi done if test -z "$haveit"; then rpathdirs="$rpathdirs $dir" fi haveit= for x in $ltrpathdirs; do if test "X$x" = "X$dir"; then haveit=yes break fi done if test -z "$haveit"; then ltrpathdirs="$ltrpathdirs $dir" fi fi ;; -l*) names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'` ;; *.la) names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'` ;; *) LIBINTL="${LIBINTL}${LIBINTL:+ }$dep" LTLIBINTL="${LTLIBINTL}${LTLIBINTL:+ }$dep" ;; esac done fi else LIBINTL="${LIBINTL}${LIBINTL:+ }-l$name" LTLIBINTL="${LTLIBINTL}${LTLIBINTL:+ }-l$name" fi fi fi done done if test "X$rpathdirs" != "X"; then if test -n "$hardcode_libdir_separator"; then alldirs= for found_dir in $rpathdirs; do alldirs="${alldirs}${alldirs:+$hardcode_libdir_separator}$found_dir" done acl_save_libdir="$libdir" libdir="$alldirs" eval flag=\"$hardcode_libdir_flag_spec\" libdir="$acl_save_libdir" LIBINTL="${LIBINTL}${LIBINTL:+ }$flag" else for found_dir in $rpathdirs; do acl_save_libdir="$libdir" libdir="$found_dir" eval flag=\"$hardcode_libdir_flag_spec\" libdir="$acl_save_libdir" LIBINTL="${LIBINTL}${LIBINTL:+ }$flag" done fi fi if test "X$ltrpathdirs" != "X"; then for found_dir in $ltrpathdirs; do LTLIBINTL="${LTLIBINTL}${LTLIBINTL:+ }-R$found_dir" done fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU gettext in libintl" >&5 $as_echo_n "checking for GNU gettext in libintl... " >&6; } if eval \${$gt_func_gnugettext_libintl+:} false; then : $as_echo_n "(cached) " >&6 else gt_save_CPPFLAGS="$CPPFLAGS" CPPFLAGS="$CPPFLAGS $INCINTL" gt_save_LIBS="$LIBS" LIBS="$LIBS $LIBINTL" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include $gt_revision_test_code extern int _nl_msg_cat_cntr; extern #ifdef __cplusplus "C" #endif const char *_nl_expand_alias (const char *); int main () { bindtextdomain ("", ""); return * gettext ("")$gt_expression_test_code + _nl_msg_cat_cntr + *_nl_expand_alias ("") ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : eval "$gt_func_gnugettext_libintl=yes" else eval "$gt_func_gnugettext_libintl=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" != yes; } && test -n "$LIBICONV"; then LIBS="$LIBS $LIBICONV" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include $gt_revision_test_code extern int _nl_msg_cat_cntr; extern #ifdef __cplusplus "C" #endif const char *_nl_expand_alias (const char *); int main () { bindtextdomain ("", ""); return * gettext ("")$gt_expression_test_code + _nl_msg_cat_cntr + *_nl_expand_alias ("") ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : LIBINTL="$LIBINTL $LIBICONV" LTLIBINTL="$LTLIBINTL $LTLIBICONV" eval "$gt_func_gnugettext_libintl=yes" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi CPPFLAGS="$gt_save_CPPFLAGS" LIBS="$gt_save_LIBS" fi eval ac_res=\$$gt_func_gnugettext_libintl { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi if { eval "gt_val=\$$gt_func_gnugettext_libc"; test "$gt_val" = "yes"; } \ || { { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" = "yes"; } \ && test "$PACKAGE" != gettext-runtime \ && test "$PACKAGE" != gettext-tools; }; then gt_use_preinstalled_gnugettext=yes else LIBINTL= LTLIBINTL= INCINTL= fi if test -n "$INTL_MACOSX_LIBS"; then if test "$gt_use_preinstalled_gnugettext" = "yes" \ || test "$nls_cv_use_gnu_gettext" = "yes"; then LIBINTL="$LIBINTL $INTL_MACOSX_LIBS" LTLIBINTL="$LTLIBINTL $INTL_MACOSX_LIBS" fi fi if test "$gt_use_preinstalled_gnugettext" = "yes" \ || test "$nls_cv_use_gnu_gettext" = "yes"; then $as_echo "#define ENABLE_NLS 1" >>confdefs.h else USE_NLS=no fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use NLS" >&5 $as_echo_n "checking whether to use NLS... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $USE_NLS" >&5 $as_echo "$USE_NLS" >&6; } if test "$USE_NLS" = "yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking where the gettext function comes from" >&5 $as_echo_n "checking where the gettext function comes from... " >&6; } if test "$gt_use_preinstalled_gnugettext" = "yes"; then if { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" = "yes"; }; then gt_source="external libintl" else gt_source="libc" fi else gt_source="included intl directory" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gt_source" >&5 $as_echo "$gt_source" >&6; } fi if test "$USE_NLS" = "yes"; then if test "$gt_use_preinstalled_gnugettext" = "yes"; then if { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" = "yes"; }; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to link with libintl" >&5 $as_echo_n "checking how to link with libintl... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIBINTL" >&5 $as_echo "$LIBINTL" >&6; } for element in $INCINTL; do haveit= for x in $CPPFLAGS; do acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" eval x=\"$x\" exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" if test "X$x" = "X$element"; then haveit=yes break fi done if test -z "$haveit"; then CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }$element" fi done fi $as_echo "#define HAVE_GETTEXT 1" >>confdefs.h $as_echo "#define HAVE_DCGETTEXT 1" >>confdefs.h fi POSUB=po fi INTLLIBS="$LIBINTL" ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5 $as_echo_n "checking whether $CC understands -c and -o together... " >&6; } if ${am_cv_prog_cc_c_o+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF # Make sure it works both with $CC and with simple cc. # Following AC_PROG_CC_C_O, we do the test twice because some # compilers refuse to overwrite an existing .o file with -o, # though they will create one. am_cv_prog_cc_c_o=yes for am_i in 1 2; do if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5 ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } \ && test -f conftest2.$ac_objext; then : OK else am_cv_prog_cc_c_o=no break fi done rm -f core conftest* unset am_i fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5 $as_echo "$am_cv_prog_cc_c_o" >&6; } if test "$am_cv_prog_cc_c_o" != yes; then # Losing compiler, so override with the script. # FIXME: It is wrong to rewrite CC. # But if we don't then we get into trouble of one sort or another. # A longer-term fix would be to have automake use am__CC in this case, # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" CC="$am_aux_dir/compile $CC" fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu depcc="$CC" am_compiler_list= { $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 $as_echo_n "checking dependency style of $depcc... " >&6; } if ${am_cv_CC_dependencies_compiler_type+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named 'D' -- because '-MD' means "put the output # in D". rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_CC_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` fi am__universal=false case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with '-c' and '-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle '-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # After this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested. if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_CC_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_CC_dependencies_compiler_type=none fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 $as_echo "$am_cv_CC_dependencies_compiler_type" >&6; } CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type if test "x$enable_dependency_tracking" != xno \ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then am__fastdepCC_TRUE= am__fastdepCC_FALSE='#' else am__fastdepCC_TRUE='#' am__fastdepCC_FALSE= fi # Extract the first word of "rm", so it can be a program name with args. set dummy rm; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_RM+:} false; then : $as_echo_n "(cached) " >&6 else case $RM in [\\/]* | ?:[\\/]*) ac_cv_path_RM="$RM" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_RM="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_path_RM" && ac_cv_path_RM="rm" ;; esac fi RM=$ac_cv_path_RM if test -n "$RM"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RM" >&5 $as_echo "$RM" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 $as_echo_n "checking whether ln -s works... " >&6; } LN_S=$as_ln_s if test "$LN_S" = "ln -s"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 $as_echo "no, using $LN_S" >&6; } fi # Enable large file support. # Check whether --enable-largefile was given. if test "${enable_largefile+set}" = set; then : enableval=$enable_largefile; fi if test "$enable_largefile" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for special C compiler options needed for large files" >&5 $as_echo_n "checking for special C compiler options needed for large files... " >&6; } if ${ac_cv_sys_largefile_CC+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_sys_largefile_CC=no if test "$GCC" != yes; then ac_save_CC=$CC while :; do # IRIX 6.2 and later do not support large files by default, # so use the C compiler's -n32 option if that helps. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : break fi rm -f core conftest.err conftest.$ac_objext CC="$CC -n32" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_largefile_CC=' -n32'; break fi rm -f core conftest.err conftest.$ac_objext break done CC=$ac_save_CC rm -f conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_CC" >&5 $as_echo "$ac_cv_sys_largefile_CC" >&6; } if test "$ac_cv_sys_largefile_CC" != no; then CC=$CC$ac_cv_sys_largefile_CC fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _FILE_OFFSET_BITS value needed for large files" >&5 $as_echo_n "checking for _FILE_OFFSET_BITS value needed for large files... " >&6; } if ${ac_cv_sys_file_offset_bits+:} false; then : $as_echo_n "(cached) " >&6 else while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_file_offset_bits=no; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _FILE_OFFSET_BITS 64 #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_file_offset_bits=64; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_sys_file_offset_bits=unknown break done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_file_offset_bits" >&5 $as_echo "$ac_cv_sys_file_offset_bits" >&6; } case $ac_cv_sys_file_offset_bits in #( no | unknown) ;; *) cat >>confdefs.h <<_ACEOF #define _FILE_OFFSET_BITS $ac_cv_sys_file_offset_bits _ACEOF ;; esac rm -rf conftest* if test $ac_cv_sys_file_offset_bits = unknown; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _LARGE_FILES value needed for large files" >&5 $as_echo_n "checking for _LARGE_FILES value needed for large files... " >&6; } if ${ac_cv_sys_large_files+:} false; then : $as_echo_n "(cached) " >&6 else while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_large_files=no; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _LARGE_FILES 1 #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_large_files=1; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_sys_large_files=unknown break done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_large_files" >&5 $as_echo "$ac_cv_sys_large_files" >&6; } case $ac_cv_sys_large_files in #( no | unknown) ;; *) cat >>confdefs.h <<_ACEOF #define _LARGE_FILES $ac_cv_sys_large_files _ACEOF ;; esac rm -rf conftest* fi fi # default value## supported_fs="" ##enable-all## # Check whether --enable-all was given. if test "${enable_all+set}" = set; then : enableval=$enable_all; enable_all=yes fi if test "$enable_all" = yes; then ENABLE_ALL_TRUE= ENABLE_ALL_FALSE='#' else ENABLE_ALL_TRUE='#' ENABLE_ALL_FALSE= fi if test "$enable_all" = "yes"; then enable_xfs="yes" enable_extfs="yes" enable_reiserfs="yes" enable_reiser4="yes" enable_hfsp="yes" enable_fat="yes" enable_exfat="yes" enable_ntfs="yes" enable_ufs="yes" enable_vmfs="yes" enable_jfs="yes" enable_btrfs="yes" enable_minix="yes" enable_f2fs="yes" enable_nilfs2="yes" fi ORIGINAL_CFLAGS="$CFLAGS" if test "x$GCC" = "xyes"; then case " $CFLAGS " in *\ \ -Wall\ \ *) ;; *) CFLAGS="$CFLAGS -Wall" ;; esac fi if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_PKG_CONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi PKG_CONFIG=$ac_cv_path_PKG_CONFIG if test -n "$PKG_CONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 $as_echo "$PKG_CONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_path_PKG_CONFIG"; then ac_pt_PKG_CONFIG=$PKG_CONFIG # Extract the first word of "pkg-config", so it can be a program name with args. set dummy pkg-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $ac_pt_PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG if test -n "$ac_pt_PKG_CONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5 $as_echo "$ac_pt_PKG_CONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_pt_PKG_CONFIG" = x; then PKG_CONFIG="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac PKG_CONFIG=$ac_pt_PKG_CONFIG fi else PKG_CONFIG="$ac_cv_path_PKG_CONFIG" fi fi if test -n "$PKG_CONFIG"; then _pkg_min_version=0.9.0 { $as_echo "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5 $as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; } if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } PKG_CONFIG="" fi fi pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for UUID" >&5 $as_echo_n "checking for UUID... " >&6; } if test -n "$UUID_CFLAGS"; then pkg_cv_UUID_CFLAGS="$UUID_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"uuid\""; } >&5 ($PKG_CONFIG --exists --print-errors "uuid") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_UUID_CFLAGS=`$PKG_CONFIG --cflags "uuid" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$UUID_LIBS"; then pkg_cv_UUID_LIBS="$UUID_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"uuid\""; } >&5 ($PKG_CONFIG --exists --print-errors "uuid") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_UUID_LIBS=`$PKG_CONFIG --libs "uuid" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then UUID_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "uuid" 2>&1` else UUID_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "uuid" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$UUID_PKG_ERRORS" >&5 exit elif test $pkg_failed = untried; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } exit else UUID_CFLAGS=$pkg_cv_UUID_CFLAGS UUID_LIBS=$pkg_cv_UUID_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi uuidcfg=`pkg-config --cflags --libs uuid` { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthread" >&5 $as_echo_n "checking for pthread_create in -lpthread... " >&6; } if ${ac_cv_lib_pthread_pthread_create+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lpthread $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pthread_create (); int main () { return pthread_create (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_pthread_pthread_create=yes else ac_cv_lib_pthread_pthread_create=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_create" >&5 $as_echo "$ac_cv_lib_pthread_pthread_create" >&6; } if test "x$ac_cv_lib_pthread_pthread_create" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBPTHREAD 1 _ACEOF LIBS="-lpthread $LIBS" else as_fn_error $? "*** pthread library (libpthread) not found" "$LINENO" 5 fi ##ext2/3## # Check whether --enable-extfs was given. if test "${enable_extfs+set}" = set; then : enableval=$enable_extfs; enable_extfs=yes else enable_extfs=no fi if test "$enable_extfs" = yes; then ENABLE_EXTFS_TRUE= ENABLE_EXTFS_FALSE='#' else ENABLE_EXTFS_TRUE='#' ENABLE_EXTFS_FALSE= fi if test "$enable_extfs" = "yes"; then #check library of some filesystems { $as_echo "$as_me:${as_lineno-$LINENO}: checking for EXT2/3 Library and Header files ... ..." >&5 $as_echo "$as_me: checking for EXT2/3 Library and Header files ... ..." >&6;} ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 $as_echo_n "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if ${ac_cv_prog_CPP+:} false; then : $as_echo_n "(cached) " >&6 else # Double quotes because CPP needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 $as_echo "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } if ${ac_cv_path_GREP+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_GREP" || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 $as_echo "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } if ${ac_cv_path_EGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_EGREP" || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 $as_echo "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in ext2fs/ext2fs.h do : ac_fn_c_check_header_mongrel "$LINENO" "ext2fs/ext2fs.h" "ac_cv_header_ext2fs_ext2fs_h" "$ac_includes_default" if test "x$ac_cv_header_ext2fs_ext2fs_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_EXT2FS_EXT2FS_H 1 _ACEOF else as_fn_error $? "*** EXT2/3 header files (ext2fs/ext2fs.h) not found" "$LINENO" 5 fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ext2fs_initialize in -lext2fs" >&5 $as_echo_n "checking for ext2fs_initialize in -lext2fs... " >&6; } if ${ac_cv_lib_ext2fs_ext2fs_initialize+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lext2fs $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char ext2fs_initialize (); int main () { return ext2fs_initialize (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_ext2fs_ext2fs_initialize=yes else ac_cv_lib_ext2fs_ext2fs_initialize=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ext2fs_ext2fs_initialize" >&5 $as_echo "$ac_cv_lib_ext2fs_ext2fs_initialize" >&6; } if test "x$ac_cv_lib_ext2fs_ext2fs_initialize" = xyes; then : true else as_fn_error $? "*** EXT2/3 library (libext2fs) not found" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking version of libextfs" >&5 $as_echo_n "checking version of libextfs... " >&6; } pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for EXT2FS" >&5 $as_echo_n "checking for EXT2FS... " >&6; } if test -n "$EXT2FS_CFLAGS"; then pkg_cv_EXT2FS_CFLAGS="$EXT2FS_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"ext2fs >= 1.42\""; } >&5 ($PKG_CONFIG --exists --print-errors "ext2fs >= 1.42") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_EXT2FS_CFLAGS=`$PKG_CONFIG --cflags "ext2fs >= 1.42" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$EXT2FS_LIBS"; then pkg_cv_EXT2FS_LIBS="$EXT2FS_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"ext2fs >= 1.42\""; } >&5 ($PKG_CONFIG --exists --print-errors "ext2fs >= 1.42") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_EXT2FS_LIBS=`$PKG_CONFIG --libs "ext2fs >= 1.42" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then EXT2FS_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "ext2fs >= 1.42" 2>&1` else EXT2FS_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "ext2fs >= 1.42" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$EXT2FS_PKG_ERRORS" >&5 as_fn_error $? "Package requirements (ext2fs >= 1.42) were not met: $EXT2FS_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. Alternatively, you may set the environment variables EXT2FS_CFLAGS and EXT2FS_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details." "$LINENO" 5 elif test $pkg_failed = untried; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. Alternatively, you may set the environment variables EXT2FS_CFLAGS and EXT2FS_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. To get pkg-config, see . See \`config.log' for more details" "$LINENO" 5; } else EXT2FS_CFLAGS=$pkg_cv_EXT2FS_CFLAGS EXT2FS_LIBS=$pkg_cv_EXT2FS_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } extfs_version=`pkg-config --modversion ext2fs` fi supported_fs=$supported_fs" extfs" fi #end of check extfs ##XFS## # Check whether --enable-xfs was given. if test "${enable_xfs+set}" = set; then : enableval=$enable_xfs; enable_xfs=yes else enable_xfs=no fi if test "$enable_xfs" = yes; then ENABLE_XFS_TRUE= ENABLE_XFS_FALSE='#' else ENABLE_XFS_TRUE='#' ENABLE_XFS_FALSE= fi if test "$enable_xfs" = "yes"; then supported_fs=$supported_fs" xfs" xfs_version="build-in" fi #end of check xfs ##reiserfs## # Check whether --enable-reiserfs was given. if test "${enable_reiserfs+set}" = set; then : enableval=$enable_reiserfs; enable_reiserfs=yes else enable_reiserfs=no fi if test "$enable_reiserfs" = yes; then ENABLE_REISERFS_TRUE= ENABLE_REISERFS_FALSE='#' else ENABLE_REISERFS_TRUE='#' ENABLE_REISERFS_FALSE= fi if test "$enable_reiserfs" = "yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Reiserfs Library and Header files ... ..." >&5 $as_echo "$as_me: checking for Reiserfs Library and Header files ... ..." >&6;} for ac_header in reiserfs/reiserfs.h do : ac_fn_c_check_header_mongrel "$LINENO" "reiserfs/reiserfs.h" "ac_cv_header_reiserfs_reiserfs_h" "$ac_includes_default" if test "x$ac_cv_header_reiserfs_reiserfs_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_REISERFS_REISERFS_H 1 _ACEOF else as_fn_error $? "*** reiserfs header files (reiserfs/reiserfs.h) not found" "$LINENO" 5 fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for reiserfs_fs_open in -lreiserfs" >&5 $as_echo_n "checking for reiserfs_fs_open in -lreiserfs... " >&6; } if ${ac_cv_lib_reiserfs_reiserfs_fs_open+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lreiserfs $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char reiserfs_fs_open (); int main () { return reiserfs_fs_open (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_reiserfs_reiserfs_fs_open=yes else ac_cv_lib_reiserfs_reiserfs_fs_open=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_reiserfs_reiserfs_fs_open" >&5 $as_echo "$ac_cv_lib_reiserfs_reiserfs_fs_open" >&6; } if test "x$ac_cv_lib_reiserfs_reiserfs_fs_open" = xyes; then : true else as_fn_error $? "*** Reiserfs library (libreiserfs) not found" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for file_dal_open in -ldal" >&5 $as_echo_n "checking for file_dal_open in -ldal... " >&6; } if ${ac_cv_lib_dal_file_dal_open+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldal $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char file_dal_open (); int main () { return file_dal_open (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dal_file_dal_open=yes else ac_cv_lib_dal_file_dal_open=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dal_file_dal_open" >&5 $as_echo "$ac_cv_lib_dal_file_dal_open" >&6; } if test "x$ac_cv_lib_dal_file_dal_open" = xyes; then : true else as_fn_error $? "*** Reiserfs depend library (libdal) not found" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking version of libreiserfs" >&5 $as_echo_n "checking version of libreiserfs... " >&6; } supported_fs=$supported_fs" reiserfs" reiserfs_version="unknown, suggest 0.3.0.5" fi #end of check reiserfs ##reiser4## # Check whether --enable-reiser4 was given. if test "${enable_reiser4+set}" = set; then : enableval=$enable_reiser4; enable_reiser4=yes else enable_reiser4=no fi if test "$enable_reiser4" = yes; then ENABLE_REISER4_TRUE= ENABLE_REISER4_FALSE='#' else ENABLE_REISER4_TRUE='#' ENABLE_REISER4_FALSE= fi if test "$enable_reiser4" = "yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Reiser4 Library and Header files ... ..." >&5 $as_echo "$as_me: checking for Reiser4 Library and Header files ... ..." >&6;} for ac_header in reiser4/libreiser4.h do : ac_fn_c_check_header_mongrel "$LINENO" "reiser4/libreiser4.h" "ac_cv_header_reiser4_libreiser4_h" "$ac_includes_default" if test "x$ac_cv_header_reiser4_libreiser4_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_REISER4_LIBREISER4_H 1 _ACEOF else as_fn_error $? "*** reiser4 header files (reiser4/libreiser4.h) not found" "$LINENO" 5 fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for aal_device_open in -laal" >&5 $as_echo_n "checking for aal_device_open in -laal... " >&6; } if ${ac_cv_lib_aal_aal_device_open+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-laal $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char aal_device_open (); int main () { return aal_device_open (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_aal_aal_device_open=yes else ac_cv_lib_aal_aal_device_open=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_aal_aal_device_open" >&5 $as_echo "$ac_cv_lib_aal_aal_device_open" >&6; } if test "x$ac_cv_lib_aal_aal_device_open" = xyes; then : true else as_fn_error $? "*** Reiser4 depend library (libaal) not found" "$LINENO" 5 fi supported_fs=$supported_fs" reiser4" reiser4_version="unknown, suggest 1.0.6" fi #end of check reiser4 ##hfs plus## # Check whether --enable-hfsp was given. if test "${enable_hfsp+set}" = set; then : enableval=$enable_hfsp; enable_hfsp=yes else enable_hfsp=no fi if test "$enable_hfsp" = yes; then ENABLE_HFSP_TRUE= ENABLE_HFSP_FALSE='#' else ENABLE_HFSP_TRUE='#' ENABLE_HFSP_FALSE= fi if test "$enable_hfsp" = "yes"; then supported_fs=$supported_fs" hfs-plus" hfs_plus_version="build-in" fi #end of check hfsplus ##fat## # Check whether --enable-fat was given. if test "${enable_fat+set}" = set; then : enableval=$enable_fat; enable_fat=yes else enable_fat=no fi if test "$enable_fat" = yes; then ENABLE_FAT_TRUE= ENABLE_FAT_FALSE='#' else ENABLE_FAT_TRUE='#' ENABLE_FAT_FALSE= fi if test "$enable_fat" = "yes"; then supported_fs=$supported_fs" fat" fat_version="build-in" fi #end of check fat ##exfat## # Check whether --enable-exfat was given. if test "${enable_exfat+set}" = set; then : enableval=$enable_exfat; enable_exfat=yes else enable_exfat=no fi if test "$enable_exfat" = yes; then ENABLE_EXFAT_TRUE= ENABLE_EXFAT_FALSE='#' else ENABLE_EXFAT_TRUE='#' ENABLE_EXFAT_FALSE= fi if test "$enable_exfat" = "yes"; then supported_fs=$supported_fs" exfat" exfat_version="build-in" fi #end of check exfat ##f2fs## # Check whether --enable-f2fs was given. if test "${enable_f2fs+set}" = set; then : enableval=$enable_f2fs; enable_f2fs=yes else enable_f2fs=no fi if test "$enable_f2fs" = yes; then ENABLE_F2FS_TRUE= ENABLE_F2FS_FALSE='#' else ENABLE_F2FS_TRUE='#' ENABLE_F2FS_FALSE= fi if test "$enable_f2fs" = "yes"; then supported_fs=$supported_fs" f2fs" f2fs_version="build-in" fi #end of check f2fs ##nilfs2## # Check whether --enable-nilfs2 was given. if test "${enable_nilfs2+set}" = set; then : enableval=$enable_nilfs2; enable_nilfs2=yes else enable_nilfs2=no fi if test "$enable_nilfs2" = yes; then ENABLE_NILFS2_TRUE= ENABLE_NILFS2_FALSE='#' else ENABLE_NILFS2_TRUE='#' ENABLE_NILFS2_FALSE= fi if test "$enable_nilfs2" = "yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for NILFS2 header files ... ..." >&5 $as_echo "$as_me: checking for NILFS2 header files ... ..." >&6;} for ac_header in ctype.h fcntl.h grp.h libintl.h limits.h linux/magic.h \ linux/types.h locale.h mntent.h mqueue.h paths.h pwd.h \ semaphore.h stdlib.h string.h strings.h sys/ioctl.h \ sys/mount.h sys/time.h syslog.h sys/stat.h time.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in nilfs.h do : ac_fn_c_check_header_mongrel "$LINENO" "nilfs.h" "ac_cv_header_nilfs_h" "$ac_includes_default" if test "x$ac_cv_header_nilfs_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_NILFS_H 1 _ACEOF else as_fn_error $? "*** nilfs2 header files (nilfs.h) not found" "$LINENO" 5 fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for nilfs_open in -lnilfs" >&5 $as_echo_n "checking for nilfs_open in -lnilfs... " >&6; } if ${ac_cv_lib_nilfs_nilfs_open+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lnilfs $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char nilfs_open (); int main () { return nilfs_open (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_nilfs_nilfs_open=yes else ac_cv_lib_nilfs_nilfs_open=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nilfs_nilfs_open" >&5 $as_echo "$ac_cv_lib_nilfs_nilfs_open" >&6; } if test "x$ac_cv_lib_nilfs_nilfs_open" = xyes; then : true else as_fn_error $? "*** nilfs2 depend library (libnilfs) not found" "$LINENO" 5 fi supported_fs=$supported_fs" nilfs2" nilfs2_version="unknown, suggest 2.3.2" fi #end of check nilfs2 ##NTFS## # Check whether --enable-ntfs was given. if test "${enable_ntfs+set}" = set; then : enableval=$enable_ntfs; enable_ntfs=yes else enable_ntfs=no fi if test "$enable_ntfs" = "yes"; then ntfs_3g_h=0 ntfs_3g_l=0 ntfsprogs_h=0 ntfsprogs_l=0 #check library of some filesystems { $as_echo "$as_me:${as_lineno-$LINENO}: checking for NTFS-3g Library and Header files ... ..." >&5 $as_echo "$as_me: checking for NTFS-3g Library and Header files ... ..." >&6;} for ac_header in ntfs-3g/misc.h do : ac_fn_c_check_header_mongrel "$LINENO" "ntfs-3g/misc.h" "ac_cv_header_ntfs_3g_misc_h" "$ac_includes_default" if test "x$ac_cv_header_ntfs_3g_misc_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_NTFS_3G_MISC_H 1 _ACEOF ntfs_3g_h=1 else { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: *** NTFS(libntfs-3g-dev) header not found" >&5 $as_echo "$as_me: WARNING: *** NTFS(libntfs-3g-dev) header not found" >&2;} fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ntfs_mount in -lntfs-3g" >&5 $as_echo_n "checking for ntfs_mount in -lntfs-3g... " >&6; } if ${ac_cv_lib_ntfs_3g_ntfs_mount+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lntfs-3g $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char ntfs_mount (); int main () { return ntfs_mount (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_ntfs_3g_ntfs_mount=yes else ac_cv_lib_ntfs_3g_ntfs_mount=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ntfs_3g_ntfs_mount" >&5 $as_echo "$ac_cv_lib_ntfs_3g_ntfs_mount" >&6; } if test "x$ac_cv_lib_ntfs_3g_ntfs_mount" = xyes; then : ntfs_3g_l=1 else { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: *** ntfs depend library (libntfs-3g) not found" >&5 $as_echo "$as_me: WARNING: *** ntfs depend library (libntfs-3g) not found" >&2;} fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for NTFS Library and Header files ... ..." >&5 $as_echo "$as_me: checking for NTFS Library and Header files ... ..." >&6;} for ac_header in ntfs/version.h do : ac_fn_c_check_header_mongrel "$LINENO" "ntfs/version.h" "ac_cv_header_ntfs_version_h" "$ac_includes_default" if test "x$ac_cv_header_ntfs_version_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_NTFS_VERSION_H 1 _ACEOF ntfsprogs_h=1 else { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: *** NTFS(ntfsprogs) header not found" >&5 $as_echo "$as_me: WARNING: *** NTFS(ntfsprogs) header not found" >&2;} fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ntfs_mount in -lntfs" >&5 $as_echo_n "checking for ntfs_mount in -lntfs... " >&6; } if ${ac_cv_lib_ntfs_ntfs_mount+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lntfs $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char ntfs_mount (); int main () { return ntfs_mount (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_ntfs_ntfs_mount=yes else ac_cv_lib_ntfs_ntfs_mount=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ntfs_ntfs_mount" >&5 $as_echo "$ac_cv_lib_ntfs_ntfs_mount" >&6; } if test "x$ac_cv_lib_ntfs_ntfs_mount" = xyes; then : ntfsprogs_l=1 else { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: *** ntfsprogs library (libntfs) not found" >&5 $as_echo "$as_me: WARNING: *** ntfsprogs library (libntfs) not found" >&2;} fi fi if test "$ntfs_3g_l" = 1; then ENABLE_NTFS_3G_TRUE= ENABLE_NTFS_3G_FALSE='#' else ENABLE_NTFS_3G_TRUE='#' ENABLE_NTFS_3G_FALSE= fi if test "$ntfsprogs_l" = 1; then ENABLE_NTFS_PROGS_TRUE= ENABLE_NTFS_PROGS_FALSE='#' else ENABLE_NTFS_PROGS_TRUE='#' ENABLE_NTFS_PROGS_FALSE= fi if test "$ntfsprogs_l" = 1 -o "$ntfs_3g_l" = 1; then ENABLE_NTFS_TRUE= ENABLE_NTFS_FALSE='#' else ENABLE_NTFS_TRUE='#' ENABLE_NTFS_FALSE= fi define_ntfs_version="ntfs-3g" if test "$ntfs_3g_h" = 1 -a "$ntfs_3g_l" = 1; then supported_fs=$supported_fs" ntfs" ntfs_version="ntfs-3g" pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for NTFS" >&5 $as_echo_n "checking for NTFS... " >&6; } if test -n "$NTFS_CFLAGS"; then pkg_cv_NTFS_CFLAGS="$NTFS_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libntfs-3g >= 2010\""; } >&5 ($PKG_CONFIG --exists --print-errors "libntfs-3g >= 2010") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_NTFS_CFLAGS=`$PKG_CONFIG --cflags "libntfs-3g >= 2010" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$NTFS_LIBS"; then pkg_cv_NTFS_LIBS="$NTFS_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libntfs-3g >= 2010\""; } >&5 ($PKG_CONFIG --exists --print-errors "libntfs-3g >= 2010") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_NTFS_LIBS=`$PKG_CONFIG --libs "libntfs-3g >= 2010" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then NTFS_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libntfs-3g >= 2010" 2>&1` else NTFS_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libntfs-3g >= 2010" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$NTFS_PKG_ERRORS" >&5 as_fn_error $? "Package requirements (libntfs-3g >= 2010) were not met: $NTFS_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. Alternatively, you may set the environment variables NTFS_CFLAGS and NTFS_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details." "$LINENO" 5 elif test $pkg_failed = untried; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. Alternatively, you may set the environment variables NTFS_CFLAGS and NTFS_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. To get pkg-config, see . See \`config.log' for more details" "$LINENO" 5; } else NTFS_CFLAGS=$pkg_cv_NTFS_CFLAGS NTFS_LIBS=$pkg_cv_NTFS_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } ntfs_version=`pkg-config --modversion libntfs-3g` fi elif test "$ntfsprogs_h" = 1 -a "$ntfsprogs_l" = 1; then ntfs_version="unknown ntfsprogs, suggest 0:9:0" fi #end of check ntfs ##UFS## # Check whether --enable-ufs was given. if test "${enable_ufs+set}" = set; then : enableval=$enable_ufs; enable_ufs=yes else enable_ufs=no fi if test "$enable_ufs" = yes; then ENABLE_UFS_TRUE= ENABLE_UFS_FALSE='#' else ENABLE_UFS_TRUE='#' ENABLE_UFS_FALSE= fi if test "$enable_ufs" = "yes"; then #check library of some filesystems { $as_echo "$as_me:${as_lineno-$LINENO}: checking for UFS Library ... ..." >&5 $as_echo "$as_me: checking for UFS Library ... ..." >&6;} { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ufs_disk_fillout in -lufs" >&5 $as_echo_n "checking for ufs_disk_fillout in -lufs... " >&6; } if ${ac_cv_lib_ufs_ufs_disk_fillout+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lufs $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char ufs_disk_fillout (); int main () { return ufs_disk_fillout (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_ufs_ufs_disk_fillout=yes else ac_cv_lib_ufs_ufs_disk_fillout=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ufs_ufs_disk_fillout" >&5 $as_echo "$ac_cv_lib_ufs_ufs_disk_fillout" >&6; } if test "x$ac_cv_lib_ufs_ufs_disk_fillout" = xyes; then : true else as_fn_error $? "*** ufs depend library (libufs2) not found" "$LINENO" 5 fi supported_fs=$supported_fs" ufs" ufs_version="unknown, suggest 7.0-2" fi #end of check ufs ##VMFS## # Check whether --enable-vmfs was given. if test "${enable_vmfs+set}" = set; then : enableval=$enable_vmfs; enable_vmfs=yes else enable_vmfs=no fi if test "$enable_vmfs" = yes; then ENABLE_VMFS_TRUE= ENABLE_VMFS_FALSE='#' else ENABLE_VMFS_TRUE='#' ENABLE_VMFS_FALSE= fi if test "$enable_vmfs" = "yes"; then #check library of some filesystems ##AC_CHECKING([ for VMFS Library and Header files ... ]) ##AC_CHECK_HEADERS([uuid/uuid.h vmfs/vmfs.h], , ## AC_MSG_ERROR([*** VMFS(vmfs-tools) header not found])) { $as_echo "$as_me:${as_lineno-$LINENO}: checking for VMFS Library files ... ..." >&5 $as_echo "$as_me: checking for VMFS Library files ... ..." >&6;} as_ac_Lib=`$as_echo "ac_cv_lib_vmfs -luuid''_vmfs_host_init" | $as_tr_sh` { $as_echo "$as_me:${as_lineno-$LINENO}: checking for vmfs_host_init in -lvmfs -luuid" >&5 $as_echo_n "checking for vmfs_host_init in -lvmfs -luuid... " >&6; } if eval \${$as_ac_Lib+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lvmfs -luuid $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char vmfs_host_init (); int main () { return vmfs_host_init (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : eval "$as_ac_Lib=yes" else eval "$as_ac_Lib=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi eval ac_res=\$$as_ac_Lib { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then : true else as_fn_error $? "*** vmfs depend library (libvmfs) not found" "$LINENO" 5 fi supported_fs=$supported_fs" vmfs" vmfs_version="unknown" fi #end of check vmfs ##JFS## # Check whether --enable-jfs was given. if test "${enable_jfs+set}" = set; then : enableval=$enable_jfs; enable_jfs=yes else enable_jfs=no fi if test "$enable_jfs" = yes; then ENABLE_JFS_TRUE= ENABLE_JFS_FALSE='#' else ENABLE_JFS_TRUE='#' ENABLE_JFS_FALSE= fi if test "$enable_jfs" = "yes"; then #check library of some filesystems ##AC_CHECKING([ for JFS Library and Header files ... ]) ##AC_CHECK_HEADERS([uuid/uuid.h jfs/jfs_superblock.h], , ## AC_MSG_ERROR([*** JFS(libjfs) header not found])) { $as_echo "$as_me:${as_lineno-$LINENO}: checking for JFS Library files ... ..." >&5 $as_echo "$as_me: checking for JFS Library files ... ..." >&6;} as_ac_Lib=`$as_echo "ac_cv_lib_jfs -luuid''_ujfs_get_superblk" | $as_tr_sh` { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ujfs_get_superblk in -ljfs -luuid" >&5 $as_echo_n "checking for ujfs_get_superblk in -ljfs -luuid... " >&6; } if eval \${$as_ac_Lib+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ljfs -luuid $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char ujfs_get_superblk (); int main () { return ujfs_get_superblk (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : eval "$as_ac_Lib=yes" else eval "$as_ac_Lib=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi eval ac_res=\$$as_ac_Lib { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then : true else as_fn_error $? "*** jfs depend library (libjfs) not found" "$LINENO" 5 fi supported_fs=$supported_fs" jfs" jfs_version="unknown, suggest 1.1.12" fi #end of check jfs ##btrfs## # Check whether --enable-btrfs was given. if test "${enable_btrfs+set}" = set; then : enableval=$enable_btrfs; enable_btrfs=yes else enable_btrfs=no fi if test "$enable_btrfs" = yes; then ENABLE_BTRFS_TRUE= ENABLE_BTRFS_FALSE='#' else ENABLE_BTRFS_TRUE='#' ENABLE_BTRFS_FALSE= fi if test "$enable_btrfs" = yes; then for ac_header in blkid/blkid.h do : ac_fn_c_check_header_mongrel "$LINENO" "blkid/blkid.h" "ac_cv_header_blkid_blkid_h" "$ac_includes_default" if test "x$ac_cv_header_blkid_blkid_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_BLKID_BLKID_H 1 _ACEOF else as_fn_error $? "*** btrfs depend library (libblkid-dev) header not found" "$LINENO" 5 fi done supported_fs=$supported_fs" btrfs" btrfs_version="unknown" fi #end of check btrfs ##minix## # Check whether --enable-minix was given. if test "${enable_minix+set}" = set; then : enableval=$enable_minix; enable_minix=yes else enable_minix=no fi if test "$enable_minix" = yes; then ENABLE_MINIX_TRUE= ENABLE_MINIX_FALSE='#' else ENABLE_MINIX_TRUE='#' ENABLE_MINIX_FALSE= fi if test "$enable_minix" = "yes"; then supported_fs=$supported_fs" minix" minix_version="build-in" fi #end of check minix ##libncursesw## # Check whether --enable-ncursesw was given. if test "${enable_ncursesw+set}" = set; then : enableval=$enable_ncursesw; enable_ncursesw=yes fi if test "$enable_ncursesw" = yes; then ENABLE_NCURSESW_TRUE= ENABLE_NCURSESW_FALSE='#' else ENABLE_NCURSESW_TRUE='#' ENABLE_NCURSESW_FALSE= fi if test "$enable_ncursesw" = "yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Ncursesw Library and Header files ... ..." >&5 $as_echo "$as_me: checking for Ncursesw Library and Header files ... ..." >&6;} for ac_header in ncurses.h do : ac_fn_c_check_header_mongrel "$LINENO" "ncurses.h" "ac_cv_header_ncurses_h" "$ac_includes_default" if test "x$ac_cv_header_ncurses_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_NCURSES_H 1 _ACEOF else as_fn_error $? "*** ncurses header files (ncurses.h) not found" "$LINENO" 5 fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for initscr in -lncursesw" >&5 $as_echo_n "checking for initscr in -lncursesw... " >&6; } if ${ac_cv_lib_ncursesw_initscr+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lncursesw $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char initscr (); int main () { return initscr (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_ncursesw_initscr=yes else ac_cv_lib_ncursesw_initscr=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ncursesw_initscr" >&5 $as_echo "$ac_cv_lib_ncursesw_initscr" >&6; } if test "x$ac_cv_lib_ncursesw_initscr" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBNCURSESW 1 _ACEOF LIBS="-lncursesw $LIBS" else as_fn_error $? "*** Ncursesw library (libncursesw5) not found" "$LINENO" 5 fi fi ##static linking## # Check whether --enable-static was given. if test "${enable_static+set}" = set; then : enableval=$enable_static; enable_static=yes fi if test "$enable_static" = yes; then ENABLE_STATIC_TRUE= ENABLE_STATIC_FALSE='#' else ENABLE_STATIC_TRUE='#' ENABLE_STATIC_FALSE= fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for initscr in -ltinfo" >&5 $as_echo_n "checking for initscr in -ltinfo... " >&6; } if ${ac_cv_lib_tinfo_initscr+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ltinfo $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char initscr (); int main () { return initscr (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_tinfo_initscr=yes else ac_cv_lib_tinfo_initscr=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_tinfo_initscr" >&5 $as_echo "$ac_cv_lib_tinfo_initscr" >&6; } if test "x$ac_cv_lib_tinfo_initscr" = xyes; then : tinfo=1 else { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: *** tinfo library (libtinfo) not found" >&5 $as_echo "$as_me: WARNING: *** tinfo library (libtinfo) not found" >&2;} fi if test "$tinfo" = 1; then ENABLE_TINFO_TRUE= ENABLE_TINFO_FALSE='#' else ENABLE_TINFO_TRUE='#' ENABLE_TINFO_FALSE= fi ##memory tracing## # Check whether --enable-mtrace was given. if test "${enable_mtrace+set}" = set; then : enableval=$enable_mtrace; enable_memtrace=yes fi if test "$enable_memtrace" = yes; then ENABLE_MEMTRACE_TRUE= ENABLE_MEMTRACE_FALSE='#' else ENABLE_MEMTRACE_TRUE='#' ENABLE_MEMTRACE_FALSE= fi ##extra test # Check whether --enable-fs-test was given. if test "${enable_fs_test+set}" = set; then : enableval=$enable_fs_test; enable_fs_test=yes fi if test "$enable_fs_test" = yes; then ENABLE_FS_TEST_TRUE= ENABLE_FS_TEST_FALSE='#' else ENABLE_FS_TEST_TRUE='#' ENABLE_FS_TEST_FALSE= fi ac_config_headers="$ac_config_headers config.h" ac_config_files="$ac_config_files Makefile src/Makefile fail-mbr/Makefile po/Makefile.in docs/Makefile tests/Makefile" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs { $as_echo "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5 $as_echo_n "checking that generated files are newer than configure... " >&6; } if test -n "$am_sleep_pid"; then # Hide warnings about reused PIDs. wait $am_sleep_pid 2>/dev/null fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: done" >&5 $as_echo "done" >&6; } if test -n "$EXEEXT"; then am__EXEEXT_TRUE= am__EXEEXT_FALSE='#' else am__EXEEXT_TRUE='#' am__EXEEXT_FALSE= fi if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then as_fn_error $? "conditional \"AMDEP\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then as_fn_error $? "conditional \"am__fastdepCC\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then as_fn_error $? "conditional \"am__fastdepCC\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${ENABLE_ALL_TRUE}" && test -z "${ENABLE_ALL_FALSE}"; then as_fn_error $? "conditional \"ENABLE_ALL\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${ENABLE_EXTFS_TRUE}" && test -z "${ENABLE_EXTFS_FALSE}"; then as_fn_error $? "conditional \"ENABLE_EXTFS\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${ENABLE_XFS_TRUE}" && test -z "${ENABLE_XFS_FALSE}"; then as_fn_error $? "conditional \"ENABLE_XFS\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${ENABLE_REISERFS_TRUE}" && test -z "${ENABLE_REISERFS_FALSE}"; then as_fn_error $? "conditional \"ENABLE_REISERFS\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${ENABLE_REISER4_TRUE}" && test -z "${ENABLE_REISER4_FALSE}"; then as_fn_error $? "conditional \"ENABLE_REISER4\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${ENABLE_HFSP_TRUE}" && test -z "${ENABLE_HFSP_FALSE}"; then as_fn_error $? "conditional \"ENABLE_HFSP\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${ENABLE_FAT_TRUE}" && test -z "${ENABLE_FAT_FALSE}"; then as_fn_error $? "conditional \"ENABLE_FAT\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${ENABLE_EXFAT_TRUE}" && test -z "${ENABLE_EXFAT_FALSE}"; then as_fn_error $? "conditional \"ENABLE_EXFAT\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${ENABLE_F2FS_TRUE}" && test -z "${ENABLE_F2FS_FALSE}"; then as_fn_error $? "conditional \"ENABLE_F2FS\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${ENABLE_NILFS2_TRUE}" && test -z "${ENABLE_NILFS2_FALSE}"; then as_fn_error $? "conditional \"ENABLE_NILFS2\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${ENABLE_NTFS_3G_TRUE}" && test -z "${ENABLE_NTFS_3G_FALSE}"; then as_fn_error $? "conditional \"ENABLE_NTFS_3G\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${ENABLE_NTFS_PROGS_TRUE}" && test -z "${ENABLE_NTFS_PROGS_FALSE}"; then as_fn_error $? "conditional \"ENABLE_NTFS_PROGS\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${ENABLE_NTFS_TRUE}" && test -z "${ENABLE_NTFS_FALSE}"; then as_fn_error $? "conditional \"ENABLE_NTFS\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${ENABLE_UFS_TRUE}" && test -z "${ENABLE_UFS_FALSE}"; then as_fn_error $? "conditional \"ENABLE_UFS\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${ENABLE_VMFS_TRUE}" && test -z "${ENABLE_VMFS_FALSE}"; then as_fn_error $? "conditional \"ENABLE_VMFS\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${ENABLE_JFS_TRUE}" && test -z "${ENABLE_JFS_FALSE}"; then as_fn_error $? "conditional \"ENABLE_JFS\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${ENABLE_BTRFS_TRUE}" && test -z "${ENABLE_BTRFS_FALSE}"; then as_fn_error $? "conditional \"ENABLE_BTRFS\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${ENABLE_MINIX_TRUE}" && test -z "${ENABLE_MINIX_FALSE}"; then as_fn_error $? "conditional \"ENABLE_MINIX\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${ENABLE_NCURSESW_TRUE}" && test -z "${ENABLE_NCURSESW_FALSE}"; then as_fn_error $? "conditional \"ENABLE_NCURSESW\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${ENABLE_STATIC_TRUE}" && test -z "${ENABLE_STATIC_FALSE}"; then as_fn_error $? "conditional \"ENABLE_STATIC\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${ENABLE_TINFO_TRUE}" && test -z "${ENABLE_TINFO_FALSE}"; then as_fn_error $? "conditional \"ENABLE_TINFO\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${ENABLE_MEMTRACE_TRUE}" && test -z "${ENABLE_MEMTRACE_FALSE}"; then as_fn_error $? "conditional \"ENABLE_MEMTRACE\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${ENABLE_FS_TEST_TRUE}" && test -z "${ENABLE_FS_TEST_FALSE}"; then as_fn_error $? "conditional \"ENABLE_FS_TEST\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by Partclone $as_me 0.2.86, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac case $ac_config_headers in *" "*) set x $ac_config_headers; shift; ac_config_headers=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" config_headers="$ac_config_headers" config_commands="$ac_config_commands" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE --header=FILE[:TEMPLATE] instantiate the configuration header FILE Configuration files: $config_files Configuration headers: $config_headers Configuration commands: $config_commands Report bugs to ." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ Partclone config.status 0.2.86 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" Copyright (C) 2012 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' MKDIR_P='$MKDIR_P' AWK='$AWK' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append CONFIG_HEADERS " '$ac_optarg'" ac_need_defaults=false;; --he | --h) # Conflict between --help and --header as_fn_error $? "ambiguous option: \`$1' Try \`$0 --help' for more information.";; --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # # INIT-COMMANDS # # Capture the value of obsolete ALL_LINGUAS because we need it to compute # POFILES, UPDATEPOFILES, DUMMYPOFILES, GMOFILES, CATALOGS. But hide it # from automake < 1.5. eval 'OBSOLETE_ALL_LINGUAS''="$ALL_LINGUAS"' # Capture the value of LINGUAS because we need it to compute CATALOGS. LINGUAS="${LINGUAS-%UNSET%}" AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "po-directories") CONFIG_COMMANDS="$CONFIG_COMMANDS po-directories" ;; "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;; "fail-mbr/Makefile") CONFIG_FILES="$CONFIG_FILES fail-mbr/Makefile" ;; "po/Makefile.in") CONFIG_FILES="$CONFIG_FILES po/Makefile.in" ;; "docs/Makefile") CONFIG_FILES="$CONFIG_FILES docs/Makefile" ;; "tests/Makefile") CONFIG_FILES="$CONFIG_FILES tests/Makefile" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" # Set up the scripts for CONFIG_HEADERS section. # No need to generate them if there are no CONFIG_HEADERS. # This happens for instance with `./config.status Makefile'. if test -n "$CONFIG_HEADERS"; then cat >"$ac_tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF # Transform confdefs.h into an awk script `defines.awk', embedded as # here-document in config.status, that substitutes the proper values into # config.h.in to produce config.h. # Create a delimiter string that does not exist in confdefs.h, to ease # handling of long lines. ac_delim='%!_!# ' for ac_last_try in false false :; do ac_tt=`sed -n "/$ac_delim/p" confdefs.h` if test -z "$ac_tt"; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done # For the awk script, D is an array of macro values keyed by name, # likewise P contains macro parameters if any. Preserve backslash # newline sequences. ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* sed -n ' s/.\{148\}/&'"$ac_delim"'/g t rset :rset s/^[ ]*#[ ]*define[ ][ ]*/ / t def d :def s/\\$// t bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3"/p s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p d :bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3\\\\\\n"\\/p t cont s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p t cont d :cont n s/.\{148\}/&'"$ac_delim"'/g t clear :clear s/\\$// t bsnlc s/["\\]/\\&/g; s/^/"/; s/$/"/p d :bsnlc s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p b cont ' >$CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 for (key in D) D_is_set[key] = 1 FS = "" } /^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { line = \$ 0 split(line, arg, " ") if (arg[1] == "#") { defundef = arg[2] mac1 = arg[3] } else { defundef = substr(arg[1], 2) mac1 = arg[2] } split(mac1, mac2, "(") #) macro = mac2[1] prefix = substr(line, 1, index(line, defundef) - 1) if (D_is_set[macro]) { # Preserve the white space surrounding the "#". print prefix "define", macro P[macro] D[macro] next } else { # Replace #undef with comments. This is necessary, for example, # in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. if (defundef == "undef") { print "/*", prefix defundef, macro, "*/" next } } } { print } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 fi # test -n "$CONFIG_HEADERS" eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac ac_MKDIR_P=$MKDIR_P case $MKDIR_P in [\\/$]* | ?:[\\/]* ) ;; */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t s&@MKDIR_P@&$ac_MKDIR_P&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; :H) # # CONFIG_HEADER # if test x"$ac_file" != x-; then { $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" } >"$ac_tmp/config.h" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 $as_echo "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" mv "$ac_tmp/config.h" "$ac_file" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ || as_fn_error $? "could not create -" "$LINENO" 5 fi # Compute "$ac_file"'s index in $config_headers. _am_arg="$ac_file" _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $_am_arg | $_am_arg:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" || $as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$_am_arg" : 'X\(//\)[^/]' \| \ X"$_am_arg" : 'X\(//\)$' \| \ X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$_am_arg" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'`/stamp-h$_am_stamp_count ;; :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 $as_echo "$as_me: executing $ac_file commands" >&6;} ;; esac case $ac_file$ac_mode in "po-directories":C) for ac_file in $CONFIG_FILES; do # Support "outfile[:infile[:infile...]]" case "$ac_file" in *:*) ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; esac # PO directories have a Makefile.in generated from Makefile.in.in. case "$ac_file" in */Makefile.in) # Adjust a relative srcdir. ac_dir=`echo "$ac_file"|sed 's%/[^/][^/]*$%%'` ac_dir_suffix="/`echo "$ac_dir"|sed 's%^\./%%'`" ac_dots=`echo "$ac_dir_suffix"|sed 's%/[^/]*%../%g'` # In autoconf-2.13 it is called $ac_given_srcdir. # In autoconf-2.50 it is called $srcdir. test -n "$ac_given_srcdir" || ac_given_srcdir="$srcdir" case "$ac_given_srcdir" in .) top_srcdir=`echo $ac_dots|sed 's%/$%%'` ;; /*) top_srcdir="$ac_given_srcdir" ;; *) top_srcdir="$ac_dots$ac_given_srcdir" ;; esac # Treat a directory as a PO directory if and only if it has a # POTFILES.in file. This allows packages to have multiple PO # directories under different names or in different locations. if test -f "$ac_given_srcdir/$ac_dir/POTFILES.in"; then rm -f "$ac_dir/POTFILES" test -n "$as_me" && echo "$as_me: creating $ac_dir/POTFILES" || echo "creating $ac_dir/POTFILES" cat "$ac_given_srcdir/$ac_dir/POTFILES.in" | sed -e "/^#/d" -e "/^[ ]*\$/d" -e "s,.*, $top_srcdir/& \\\\," | sed -e "\$s/\(.*\) \\\\/\1/" > "$ac_dir/POTFILES" POMAKEFILEDEPS="POTFILES.in" # ALL_LINGUAS, POFILES, UPDATEPOFILES, DUMMYPOFILES, GMOFILES depend # on $ac_dir but don't depend on user-specified configuration # parameters. if test -f "$ac_given_srcdir/$ac_dir/LINGUAS"; then # The LINGUAS file contains the set of available languages. if test -n "$OBSOLETE_ALL_LINGUAS"; then test -n "$as_me" && echo "$as_me: setting ALL_LINGUAS in configure.in is obsolete" || echo "setting ALL_LINGUAS in configure.in is obsolete" fi ALL_LINGUAS_=`sed -e "/^#/d" -e "s/#.*//" "$ac_given_srcdir/$ac_dir/LINGUAS"` # Hide the ALL_LINGUAS assigment from automake < 1.5. eval 'ALL_LINGUAS''=$ALL_LINGUAS_' POMAKEFILEDEPS="$POMAKEFILEDEPS LINGUAS" else # The set of available languages was given in configure.in. # Hide the ALL_LINGUAS assigment from automake < 1.5. eval 'ALL_LINGUAS''=$OBSOLETE_ALL_LINGUAS' fi # Compute POFILES # as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).po) # Compute UPDATEPOFILES # as $(foreach lang, $(ALL_LINGUAS), $(lang).po-update) # Compute DUMMYPOFILES # as $(foreach lang, $(ALL_LINGUAS), $(lang).nop) # Compute GMOFILES # as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).gmo) case "$ac_given_srcdir" in .) srcdirpre= ;; *) srcdirpre='$(srcdir)/' ;; esac POFILES= UPDATEPOFILES= DUMMYPOFILES= GMOFILES= for lang in $ALL_LINGUAS; do POFILES="$POFILES $srcdirpre$lang.po" UPDATEPOFILES="$UPDATEPOFILES $lang.po-update" DUMMYPOFILES="$DUMMYPOFILES $lang.nop" GMOFILES="$GMOFILES $srcdirpre$lang.gmo" done # CATALOGS depends on both $ac_dir and the user's LINGUAS # environment variable. INST_LINGUAS= if test -n "$ALL_LINGUAS"; then for presentlang in $ALL_LINGUAS; do useit=no if test "%UNSET%" != "$LINGUAS"; then desiredlanguages="$LINGUAS" else desiredlanguages="$ALL_LINGUAS" fi for desiredlang in $desiredlanguages; do # Use the presentlang catalog if desiredlang is # a. equal to presentlang, or # b. a variant of presentlang (because in this case, # presentlang can be used as a fallback for messages # which are not translated in the desiredlang catalog). case "$desiredlang" in "$presentlang"*) useit=yes;; esac done if test $useit = yes; then INST_LINGUAS="$INST_LINGUAS $presentlang" fi done fi CATALOGS= if test -n "$INST_LINGUAS"; then for lang in $INST_LINGUAS; do CATALOGS="$CATALOGS $lang.gmo" done fi test -n "$as_me" && echo "$as_me: creating $ac_dir/Makefile" || echo "creating $ac_dir/Makefile" sed -e "/^POTFILES =/r $ac_dir/POTFILES" -e "/^# Makevars/r $ac_given_srcdir/$ac_dir/Makevars" -e "s|@POFILES@|$POFILES|g" -e "s|@UPDATEPOFILES@|$UPDATEPOFILES|g" -e "s|@DUMMYPOFILES@|$DUMMYPOFILES|g" -e "s|@GMOFILES@|$GMOFILES|g" -e "s|@CATALOGS@|$CATALOGS|g" -e "s|@POMAKEFILEDEPS@|$POMAKEFILEDEPS|g" "$ac_dir/Makefile.in" > "$ac_dir/Makefile" for f in "$ac_given_srcdir/$ac_dir"/Rules-*; do if test -f "$f"; then case "$f" in *.orig | *.bak | *~) ;; *) cat "$f" >> "$ac_dir/Makefile" ;; esac fi done fi ;; esac done ;; "depfiles":C) test x"$AMDEP_TRUE" != x"" || { # Older Autoconf quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. case $CONFIG_FILES in *\'*) eval set x "$CONFIG_FILES" ;; *) set x $CONFIG_FILES ;; esac shift for mf do # Strip MF so we end up with the name of the file. mf=`echo "$mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile or not. # We used to match only the files named 'Makefile.in', but # some people rename them; so instead we look at the file content. # Grep'ing the first line is not enough: some people post-process # each Makefile.in and add a new line on top of each file to say so. # Grep'ing the whole file is not good either: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then dirpart=`$as_dirname -- "$mf" || $as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$mf" : 'X\(//\)[^/]' \| \ X"$mf" : 'X\(//\)$' \| \ X"$mf" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$mf" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` else continue fi # Extract the definition of DEPDIR, am__include, and am__quote # from the Makefile without running 'make'. DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` test -z "$DEPDIR" && continue am__include=`sed -n 's/^am__include = //p' < "$mf"` test -z "$am__include" && continue am__quote=`sed -n 's/^am__quote = //p' < "$mf"` # Find all dependency output files, they are included files with # $(DEPDIR) in their names. We invoke sed twice because it is the # simplest approach to changing $(DEPDIR) to its actual value in the # expansion. for file in `sed -n " s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do # Make sure the directory exists. test -f "$dirpart/$file" && continue fdir=`$as_dirname -- "$file" || $as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$file" : 'X\(//\)[^/]' \| \ X"$file" : 'X\(//\)$' \| \ X"$file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir=$dirpart/$fdir; as_fn_mkdir_p # echo "creating $dirpart/$file" echo '# dummy' > "$dirpart/$file" done done } ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi echo "" echo "Support File System:" echo "ext2/3/4...... $enable_extfs, $extfs_version" echo "reiserfs...... $enable_reiserfs, $reiserfs_version" echo "reiser4....... $enable_reiser4, $reiser4_version" echo "xfs........... $enable_xfs, $xfs_version" echo "ntfs.......... $enable_ntfs, $ntfs_version" echo "fat12/16/32... $enable_fat, $fat_version" echo "exfat......... $enable_exfat, $exfat_version" echo "hfs plus...... $enable_hfsp, $hfs_plus_version" echo "ufs .......... $enable_ufs, $ufs_version" echo "vmfs ......... $enable_vmfs, $vmfs_version" echo "jfs .......... $enable_jfs, $jfs_version" echo "btrfs......... $enable_btrfs, $btrfs_version" echo "minix......... $enable_minix, $minix_version" echo "f2fs.......... $enable_f2fs, $f2fs_version" echo "nilfs2.........$enable_nilfs2, $nilfs2_version" #echo $supported_fs partclone-0.2.86/configure.ac000066400000000000000000000276401262102574200160760ustar00rootroot00000000000000AC_INIT([Partclone], [0.2.86], [thomas@nchc.org.tw]) AM_INIT_AUTOMAKE([-Wall foreign]) AM_GNU_GETTEXT_VERSION([0.16.1]) AM_GNU_GETTEXT([external]) AC_PROG_CC AM_PROG_CC_C_O AC_PROG_INSTALL AC_PATH_PROG(RM, rm, rm) AC_PROG_LN_S # Enable large file support. AC_SYS_LARGEFILE # default value## supported_fs="" ##enable-all## AC_ARG_ENABLE(all, AS_HELP_STRING(--enable-all,enable all supported file system), enable_all=yes, ) AM_CONDITIONAL(ENABLE_ALL, test "$enable_all" = yes) if test "$enable_all" = "yes"; then enable_xfs="yes" enable_extfs="yes" enable_reiserfs="yes" enable_reiser4="yes" enable_hfsp="yes" enable_fat="yes" enable_exfat="yes" enable_ntfs="yes" enable_ufs="yes" enable_vmfs="yes" enable_jfs="yes" enable_btrfs="yes" enable_minix="yes" enable_f2fs="yes" enable_nilfs2="yes" fi ORIGINAL_CFLAGS="$CFLAGS" AC_SUBST(ORIGINAL_CFLAGS) if test "x$GCC" = "xyes"; then case " $CFLAGS " in *[\ \ ]-Wall[\ \ ]*) ;; *) CFLAGS="$CFLAGS -Wall" ;; esac fi dnl Check for uuid PKG_CHECK_MODULES(UUID, uuid,,exit) uuidcfg=`pkg-config --cflags --libs uuid` AC_CHECK_LIB([pthread], [pthread_create], [], AC_MSG_ERROR([*** pthread library (libpthread) not found])) ##ext2/3## AC_ARG_ENABLE(extfs, AS_HELP_STRING(--enable-extfs,enable ext2/3/4 file system), enable_extfs=yes, enable_extfs=no ) AM_CONDITIONAL(ENABLE_EXTFS, test "$enable_extfs" = yes) if test "$enable_extfs" = "yes"; then #check library of some filesystems dnl Check for EXT2/3 AC_CHECKING([ for EXT2/3 Library and Header files ... ]) AC_CHECK_HEADERS([ext2fs/ext2fs.h], , AC_MSG_ERROR([*** EXT2/3 header files (ext2fs/ext2fs.h) not found]) ) AC_CHECK_LIB([ext2fs], [ext2fs_initialize], true, AC_MSG_ERROR([*** EXT2/3 library (libext2fs) not found])) AC_MSG_CHECKING(version of libextfs) PKG_CHECK_MODULES([EXT2FS], [ext2fs >= 1.42], [extfs_version=`pkg-config --modversion ext2fs`]) supported_fs=$supported_fs" extfs" fi #end of check extfs ##XFS## AC_ARG_ENABLE(xfs, AS_HELP_STRING(--enable-xfs,enable XFS file system), enable_xfs=yes, enable_xfs=no ) AM_CONDITIONAL(ENABLE_XFS, test "$enable_xfs" = yes) if test "$enable_xfs" = "yes"; then supported_fs=$supported_fs" xfs" xfs_version="build-in" fi #end of check xfs ##reiserfs## AC_ARG_ENABLE(reiserfs, AS_HELP_STRING(--enable-reiserfs,enable REISERFS 3.6/3.6 file system), enable_reiserfs=yes, enable_reiserfs=no ) AM_CONDITIONAL(ENABLE_REISERFS, test "$enable_reiserfs" = yes) if test "$enable_reiserfs" = "yes"; then dnl Check for REISERFS AC_CHECKING([ for Reiserfs Library and Header files ... ]) AC_CHECK_HEADERS([reiserfs/reiserfs.h], , AC_MSG_ERROR([*** reiserfs header files (reiserfs/reiserfs.h) not found]) ) AC_CHECK_LIB([reiserfs], [reiserfs_fs_open], true, AC_MSG_ERROR([*** Reiserfs library (libreiserfs) not found])) AC_CHECK_LIB([dal], [file_dal_open], true, AC_MSG_ERROR([*** Reiserfs depend library (libdal) not found])) AC_MSG_CHECKING(version of libreiserfs) supported_fs=$supported_fs" reiserfs" reiserfs_version="unknown, suggest 0.3.0.5" fi #end of check reiserfs ##reiser4## AC_ARG_ENABLE(reiser4, AS_HELP_STRING(--enable-reiser4,enable Reiser4 file system), enable_reiser4=yes, enable_reiser4=no ) AM_CONDITIONAL(ENABLE_REISER4, test "$enable_reiser4" = yes) if test "$enable_reiser4" = "yes"; then dnl Check for REISER4 dnl Check uuid library which depended by REISER4 AC_CHECKING([ for Reiser4 Library and Header files ... ]) AC_CHECK_HEADERS([reiser4/libreiser4.h], , AC_MSG_ERROR([*** reiser4 header files (reiser4/libreiser4.h) not found]) ) AC_CHECK_LIB([aal], [aal_device_open], true, AC_MSG_ERROR([*** Reiser4 depend library (libaal) not found])) supported_fs=$supported_fs" reiser4" reiser4_version="unknown, suggest 1.0.6" fi #end of check reiser4 ##hfs plus## AC_ARG_ENABLE(hfsp, AS_HELP_STRING(--enable-hfsp,enable HFS plus file system), enable_hfsp=yes, enable_hfsp=no ) AM_CONDITIONAL(ENABLE_HFSP, test "$enable_hfsp" = yes) if test "$enable_hfsp" = "yes"; then supported_fs=$supported_fs" hfs-plus" hfs_plus_version="build-in" fi #end of check hfsplus ##fat## AC_ARG_ENABLE(fat, AS_HELP_STRING(--enable-fat,enable FAT file system), enable_fat=yes, enable_fat=no ) AM_CONDITIONAL(ENABLE_FAT, test "$enable_fat" = yes) if test "$enable_fat" = "yes"; then supported_fs=$supported_fs" fat" fat_version="build-in" fi #end of check fat ##exfat## AC_ARG_ENABLE(exfat, AS_HELP_STRING(--enable-exfat,enable EXFAT file system), enable_exfat=yes, enable_exfat=no ) AM_CONDITIONAL(ENABLE_EXFAT, test "$enable_exfat" = yes) if test "$enable_exfat" = "yes"; then supported_fs=$supported_fs" exfat" exfat_version="build-in" fi #end of check exfat ##f2fs## AC_ARG_ENABLE(f2fs, AS_HELP_STRING(--enable-f2fs,enable f2fs file system), enable_f2fs=yes, enable_f2fs=no ) AM_CONDITIONAL(ENABLE_F2FS, test "$enable_f2fs" = yes) if test "$enable_f2fs" = "yes"; then supported_fs=$supported_fs" f2fs" f2fs_version="build-in" fi #end of check f2fs ##nilfs2## AC_ARG_ENABLE(nilfs2, AS_HELP_STRING(--enable-nilfs2,enable nilfs2 file system), enable_nilfs2=yes, enable_nilfs2=no ) AM_CONDITIONAL(ENABLE_NILFS2, test "$enable_nilfs2" = yes) if test "$enable_nilfs2" = "yes"; then dnl Check headers which depended by NILFS2 AC_CHECKING([ for NILFS2 header files ... ]) AC_CHECK_HEADERS([ctype.h fcntl.h grp.h libintl.h limits.h linux/magic.h \ linux/types.h locale.h mntent.h mqueue.h paths.h pwd.h \ semaphore.h stdlib.h string.h strings.h sys/ioctl.h \ sys/mount.h sys/time.h syslog.h sys/stat.h time.h unistd.h]) AC_CHECK_HEADERS([nilfs.h], , AC_MSG_ERROR([*** nilfs2 header files (nilfs.h) not found]) ) AC_CHECK_LIB([nilfs], [nilfs_open], true, AC_MSG_ERROR([*** nilfs2 depend library (libnilfs) not found])) supported_fs=$supported_fs" nilfs2" nilfs2_version="unknown, suggest 2.3.2" fi #end of check nilfs2 ##NTFS## AC_ARG_ENABLE(ntfs, AS_HELP_STRING(--enable-ntfs,enable NTFS file system), enable_ntfs=yes, enable_ntfs=no ) if test "$enable_ntfs" = "yes"; then ntfs_3g_h=0 ntfs_3g_l=0 ntfsprogs_h=0 ntfsprogs_l=0 #check library of some filesystems dnl Check for NTFS-3g AC_CHECKING([ for NTFS-3g Library and Header files ... ]) AC_CHECK_HEADERS([ntfs-3g/misc.h], ntfs_3g_h=1, AC_MSG_WARN([*** NTFS(libntfs-3g-dev) header not found])) AC_CHECK_LIB([ntfs-3g], [ntfs_mount], ntfs_3g_l=1, AC_MSG_WARN([*** ntfs depend library (libntfs-3g) not found])) dnl Check for NTFSPROGS AC_CHECKING([ for NTFS Library and Header files ... ]) AC_CHECK_HEADERS([ntfs/version.h], ntfsprogs_h=1, AC_MSG_WARN([*** NTFS(ntfsprogs) header not found])) AC_CHECK_LIB([ntfs], [ntfs_mount], ntfsprogs_l=1, AC_MSG_WARN([*** ntfsprogs library (libntfs) not found])) fi AM_CONDITIONAL(ENABLE_NTFS_3G, test "$ntfs_3g_l" = 1) AM_CONDITIONAL(ENABLE_NTFS_PROGS, test "$ntfsprogs_l" = 1) AM_CONDITIONAL(ENABLE_NTFS, test "$ntfsprogs_l" = 1 -o "$ntfs_3g_l" = 1) define_ntfs_version="ntfs-3g" if test "$ntfs_3g_h" = 1 -a "$ntfs_3g_l" = 1; then supported_fs=$supported_fs" ntfs" ntfs_version="ntfs-3g" PKG_CHECK_MODULES([NTFS], [libntfs-3g >= 2010], [ntfs_version=`pkg-config --modversion libntfs-3g`]) elif test "$ntfsprogs_h" = 1 -a "$ntfsprogs_l" = 1; then ntfs_version="unknown ntfsprogs, suggest 0:9:0" fi #end of check ntfs ##UFS## AC_ARG_ENABLE(ufs, AS_HELP_STRING(--enable-ufs,enable UFS(1/2) file system), enable_ufs=yes, enable_ufs=no ) AM_CONDITIONAL(ENABLE_UFS, test "$enable_ufs" = yes) if test "$enable_ufs" = "yes"; then #check library of some filesystems dnl Check for UFS AC_CHECKING([ for UFS Library ... ]) AC_CHECK_LIB([ufs], [ufs_disk_fillout], true, AC_MSG_ERROR([*** ufs depend library (libufs2) not found])) supported_fs=$supported_fs" ufs" ufs_version="unknown, suggest 7.0-2" fi #end of check ufs ##VMFS## AC_ARG_ENABLE(vmfs, AS_HELP_STRING(--enable-vmfs,enable vmfs file system), enable_vmfs=yes, enable_vmfs=no ) AM_CONDITIONAL(ENABLE_VMFS, test "$enable_vmfs" = yes) if test "$enable_vmfs" = "yes"; then #check library of some filesystems dnl Check for VMFS ##AC_CHECKING([ for VMFS Library and Header files ... ]) ##AC_CHECK_HEADERS([uuid/uuid.h vmfs/vmfs.h], , ## AC_MSG_ERROR([*** VMFS(vmfs-tools) header not found])) AC_CHECKING([for VMFS Library files ... ]) AC_CHECK_LIB([vmfs -luuid], [vmfs_host_init], true, AC_MSG_ERROR([*** vmfs depend library (libvmfs) not found])) supported_fs=$supported_fs" vmfs" vmfs_version="unknown" fi #end of check vmfs ##JFS## AC_ARG_ENABLE(jfs, AS_HELP_STRING(--enable-jfs,enable jfs file system), enable_jfs=yes, enable_jfs=no ) AM_CONDITIONAL(ENABLE_JFS, test "$enable_jfs" = yes) if test "$enable_jfs" = "yes"; then #check library of some filesystems dnl Check for JFS ##AC_CHECKING([ for JFS Library and Header files ... ]) ##AC_CHECK_HEADERS([uuid/uuid.h jfs/jfs_superblock.h], , ## AC_MSG_ERROR([*** JFS(libjfs) header not found])) AC_CHECKING([for JFS Library files ... ]) AC_CHECK_LIB([jfs -luuid], [ujfs_get_superblk], true, AC_MSG_ERROR([*** jfs depend library (libjfs) not found])) supported_fs=$supported_fs" jfs" jfs_version="unknown, suggest 1.1.12" fi #end of check jfs ##btrfs## AC_ARG_ENABLE(btrfs, AS_HELP_STRING(--enable-btrfs,enable btrfs file system), enable_btrfs=yes, enable_btrfs=no ) AM_CONDITIONAL(ENABLE_BTRFS, test "$enable_btrfs" = yes) if test "$enable_btrfs" = yes; then AC_CHECK_HEADERS([blkid/blkid.h],, AC_MSG_ERROR([*** btrfs depend library (libblkid-dev) header not found])) supported_fs=$supported_fs" btrfs" btrfs_version="unknown" fi #end of check btrfs ##minix## AC_ARG_ENABLE(minix, AS_HELP_STRING(--enable-minix,enable minix file system), enable_minix=yes, enable_minix=no ) AM_CONDITIONAL(ENABLE_MINIX, test "$enable_minix" = yes) if test "$enable_minix" = "yes"; then supported_fs=$supported_fs" minix" minix_version="build-in" fi #end of check minix ##libncursesw## AC_ARG_ENABLE(ncursesw, AS_HELP_STRING(--enable-ncursesw,enable TEXT User Interface), enable_ncursesw=yes, ) AM_CONDITIONAL(ENABLE_NCURSESW, test "$enable_ncursesw" = yes) if test "$enable_ncursesw" = "yes"; then dnl Check for NCURSESW AC_CHECKING([ for Ncursesw Library and Header files ... ]) AC_CHECK_HEADERS([ncurses.h], , AC_MSG_ERROR([*** ncurses header files (ncurses.h) not found]) ) AC_CHECK_LIB([ncursesw], [initscr], , AC_MSG_ERROR([*** Ncursesw library (libncursesw5) not found])) fi ##static linking## AC_ARG_ENABLE(static, AS_HELP_STRING(--enable-static, enable static linking), enable_static=yes, ) AM_CONDITIONAL(ENABLE_STATIC, test "$enable_static" = yes) AC_CHECK_LIB([tinfo], [initscr], tinfo=1, AC_MSG_WARN([*** tinfo library (libtinfo) not found])) AM_CONDITIONAL(ENABLE_TINFO, test "$tinfo" = 1) ##memory tracing## AC_ARG_ENABLE(mtrace, AS_HELP_STRING(--enable-mtrace, enable memory tracing), enable_memtrace=yes, ) AM_CONDITIONAL(ENABLE_MEMTRACE, test "$enable_memtrace" = yes) ##extra test AC_ARG_ENABLE(fs-test, AS_HELP_STRING(--enable-fs-test, enable file system clone/restore test), enable_fs_test=yes, ) AM_CONDITIONAL(ENABLE_FS_TEST, test "$enable_fs_test" = yes) AC_CONFIG_HEADERS([config.h]) AC_CONFIG_FILES([ Makefile src/Makefile fail-mbr/Makefile po/Makefile.in docs/Makefile tests/Makefile ]) AC_OUTPUT echo "" echo "Support File System:" echo "ext2/3/4...... $enable_extfs, $extfs_version" echo "reiserfs...... $enable_reiserfs, $reiserfs_version" echo "reiser4....... $enable_reiser4, $reiser4_version" echo "xfs........... $enable_xfs, $xfs_version" echo "ntfs.......... $enable_ntfs, $ntfs_version" echo "fat12/16/32... $enable_fat, $fat_version" echo "exfat......... $enable_exfat, $exfat_version" echo "hfs plus...... $enable_hfsp, $hfs_plus_version" echo "ufs .......... $enable_ufs, $ufs_version" echo "vmfs ......... $enable_vmfs, $vmfs_version" echo "jfs .......... $enable_jfs, $jfs_version" echo "btrfs......... $enable_btrfs, $btrfs_version" echo "minix......... $enable_minix, $minix_version" echo "f2fs.......... $enable_f2fs, $f2fs_version" echo "nilfs2.........$enable_nilfs2, $nilfs2_version" #echo $supported_fs partclone-0.2.86/depcomp000077500000000000000000000560161262102574200151640ustar00rootroot00000000000000#! /bin/sh # depcomp - compile a program generating dependencies as side-effects scriptversion=2013-05-30.07; # UTC # Copyright (C) 1999-2014 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Alexandre Oliva . case $1 in '') echo "$0: No command. Try '$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: depcomp [--help] [--version] PROGRAM [ARGS] Run PROGRAMS ARGS to compile a file, generating dependencies as side-effects. Environment variables: depmode Dependency tracking mode. source Source file read by 'PROGRAMS ARGS'. object Object file output by 'PROGRAMS ARGS'. DEPDIR directory where to store dependencies. depfile Dependency file to output. tmpdepfile Temporary file to use when outputting dependencies. libtool Whether libtool is used (yes/no). Report bugs to . EOF exit $? ;; -v | --v*) echo "depcomp $scriptversion" exit $? ;; esac # Get the directory component of the given path, and save it in the # global variables '$dir'. Note that this directory component will # be either empty or ending with a '/' character. This is deliberate. set_dir_from () { case $1 in */*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;; *) dir=;; esac } # Get the suffix-stripped basename of the given path, and save it the # global variable '$base'. set_base_from () { base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'` } # If no dependency file was actually created by the compiler invocation, # we still have to create a dummy depfile, to avoid errors with the # Makefile "include basename.Plo" scheme. make_dummy_depfile () { echo "#dummy" > "$depfile" } # Factor out some common post-processing of the generated depfile. # Requires the auxiliary global variable '$tmpdepfile' to be set. aix_post_process_depfile () { # If the compiler actually managed to produce a dependency file, # post-process it. if test -f "$tmpdepfile"; then # Each line is of the form 'foo.o: dependency.h'. # Do two passes, one to just change these to # $object: dependency.h # and one to simply output # dependency.h: # which is needed to avoid the deleted-header problem. { sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile" sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile" } > "$depfile" rm -f "$tmpdepfile" else make_dummy_depfile fi } # A tabulation character. tab=' ' # A newline character. nl=' ' # Character ranges might be problematic outside the C locale. # These definitions help. upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ lower=abcdefghijklmnopqrstuvwxyz digits=0123456789 alpha=${upper}${lower} if test -z "$depmode" || test -z "$source" || test -z "$object"; then echo "depcomp: Variables source, object and depmode must be set" 1>&2 exit 1 fi # Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. depfile=${depfile-`echo "$object" | sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} rm -f "$tmpdepfile" # Avoid interferences from the environment. gccflag= dashmflag= # Some modes work just like other modes, but use different flags. We # parameterize here, but still list the modes in the big case below, # to make depend.m4 easier to write. Note that we *cannot* use a case # here, because this file can only contain one case statement. if test "$depmode" = hp; then # HP compiler uses -M and no extra arg. gccflag=-M depmode=gcc fi if test "$depmode" = dashXmstdout; then # This is just like dashmstdout with a different argument. dashmflag=-xM depmode=dashmstdout fi cygpath_u="cygpath -u -f -" if test "$depmode" = msvcmsys; then # This is just like msvisualcpp but w/o cygpath translation. # Just convert the backslash-escaped backslashes to single forward # slashes to satisfy depend.m4 cygpath_u='sed s,\\\\,/,g' depmode=msvisualcpp fi if test "$depmode" = msvc7msys; then # This is just like msvc7 but w/o cygpath translation. # Just convert the backslash-escaped backslashes to single forward # slashes to satisfy depend.m4 cygpath_u='sed s,\\\\,/,g' depmode=msvc7 fi if test "$depmode" = xlc; then # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information. gccflag=-qmakedep=gcc,-MF depmode=gcc fi case "$depmode" in gcc3) ## gcc 3 implements dependency tracking that does exactly what ## we want. Yay! Note: for some reason libtool 1.4 doesn't like ## it if -MD -MP comes after the -MF stuff. Hmm. ## Unfortunately, FreeBSD c89 acceptance of flags depends upon ## the command line argument order; so add the flags where they ## appear in depend2.am. Note that the slowdown incurred here ## affects only configure: in makefiles, %FASTDEP% shortcuts this. for arg do case $arg in -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;; *) set fnord "$@" "$arg" ;; esac shift # fnord shift # $arg done "$@" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi mv "$tmpdepfile" "$depfile" ;; gcc) ## Note that this doesn't just cater to obsosete pre-3.x GCC compilers. ## but also to in-use compilers like IMB xlc/xlC and the HP C compiler. ## (see the conditional assignment to $gccflag above). ## There are various ways to get dependency output from gcc. Here's ## why we pick this rather obscure method: ## - Don't want to use -MD because we'd like the dependencies to end ## up in a subdir. Having to rename by hand is ugly. ## (We might end up doing this anyway to support other compilers.) ## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like ## -MM, not -M (despite what the docs say). Also, it might not be ## supported by the other compilers which use the 'gcc' depmode. ## - Using -M directly means running the compiler twice (even worse ## than renaming). if test -z "$gccflag"; then gccflag=-MD, fi "$@" -Wp,"$gccflag$tmpdepfile" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" # The second -e expression handles DOS-style file names with drive # letters. sed -e 's/^[^:]*: / /' \ -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" ## This next piece of magic avoids the "deleted header file" problem. ## The problem is that when a header file which appears in a .P file ## is deleted, the dependency causes make to die (because there is ## typically no way to rebuild the header). We avoid this by adding ## dummy dependencies for each header file. Too bad gcc doesn't do ## this for us directly. ## Some versions of gcc put a space before the ':'. On the theory ## that the space means something, we add a space to the output as ## well. hp depmode also adds that space, but also prefixes the VPATH ## to the object. Take care to not repeat it in the output. ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; sgi) if test "$libtool" = yes; then "$@" "-Wp,-MDupdate,$tmpdepfile" else "$@" -MDupdate "$tmpdepfile" fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files echo "$object : \\" > "$depfile" # Clip off the initial element (the dependent). Don't try to be # clever and replace this with sed code, as IRIX sed won't handle # lines with more than a fixed number of characters (4096 in # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; # the IRIX cc adds comments like '#:fec' to the end of the # dependency line. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \ | tr "$nl" ' ' >> "$depfile" echo >> "$depfile" # The second pass generates a dummy entry for each header file. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ >> "$depfile" else make_dummy_depfile fi rm -f "$tmpdepfile" ;; xlc) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; aix) # The C for AIX Compiler uses -M and outputs the dependencies # in a .u file. In older versions, this file always lives in the # current directory. Also, the AIX compiler puts '$object:' at the # start of each line; $object doesn't have directory information. # Version 6 uses the directory in both cases. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then tmpdepfile1=$dir$base.u tmpdepfile2=$base.u tmpdepfile3=$dir.libs/$base.u "$@" -Wc,-M else tmpdepfile1=$dir$base.u tmpdepfile2=$dir$base.u tmpdepfile3=$dir$base.u "$@" -M fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" do test -f "$tmpdepfile" && break done aix_post_process_depfile ;; tcc) # tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26 # FIXME: That version still under development at the moment of writing. # Make that this statement remains true also for stable, released # versions. # It will wrap lines (doesn't matter whether long or short) with a # trailing '\', as in: # # foo.o : \ # foo.c \ # foo.h \ # # It will put a trailing '\' even on the last line, and will use leading # spaces rather than leading tabs (at least since its commit 0394caf7 # "Emit spaces for -MD"). "$@" -MD -MF "$tmpdepfile" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each non-empty line is of the form 'foo.o : \' or ' dep.h \'. # We have to change lines of the first kind to '$object: \'. sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile" # And for each line of the second kind, we have to emit a 'dep.h:' # dummy dependency, to avoid the deleted-header problem. sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile" rm -f "$tmpdepfile" ;; ## The order of this option in the case statement is important, since the ## shell code in configure will try each of these formats in the order ## listed in this file. A plain '-MD' option would be understood by many ## compilers, so we must ensure this comes after the gcc and icc options. pgcc) # Portland's C compiler understands '-MD'. # Will always output deps to 'file.d' where file is the root name of the # source file under compilation, even if file resides in a subdirectory. # The object file name does not affect the name of the '.d' file. # pgcc 10.2 will output # foo.o: sub/foo.c sub/foo.h # and will wrap long lines using '\' : # foo.o: sub/foo.c ... \ # sub/foo.h ... \ # ... set_dir_from "$object" # Use the source, not the object, to determine the base name, since # that's sadly what pgcc will do too. set_base_from "$source" tmpdepfile=$base.d # For projects that build the same source file twice into different object # files, the pgcc approach of using the *source* file root name can cause # problems in parallel builds. Use a locking strategy to avoid stomping on # the same $tmpdepfile. lockdir=$base.d-lock trap " echo '$0: caught signal, cleaning up...' >&2 rmdir '$lockdir' exit 1 " 1 2 13 15 numtries=100 i=$numtries while test $i -gt 0; do # mkdir is a portable test-and-set. if mkdir "$lockdir" 2>/dev/null; then # This process acquired the lock. "$@" -MD stat=$? # Release the lock. rmdir "$lockdir" break else # If the lock is being held by a different process, wait # until the winning process is done or we timeout. while test -d "$lockdir" && test $i -gt 0; do sleep 1 i=`expr $i - 1` done fi i=`expr $i - 1` done trap - 1 2 13 15 if test $i -le 0; then echo "$0: failed to acquire lock after $numtries attempts" >&2 echo "$0: check lockdir '$lockdir'" >&2 exit 1 fi if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each line is of the form `foo.o: dependent.h', # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. # Do two passes, one to just change these to # `$object: dependent.h' and one to simply `dependent.h:'. sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process this invocation # correctly. Breaking it into two sed invocations is a workaround. sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp2) # The "hp" stanza above does not work with aCC (C++) and HP's ia64 # compilers, which have integrated preprocessors. The correct option # to use with these is +Maked; it writes dependencies to a file named # 'foo.d', which lands next to the object file, wherever that # happens to be. # Much of this is similar to the tru64 case; see comments there. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then tmpdepfile1=$dir$base.d tmpdepfile2=$dir.libs/$base.d "$@" -Wc,+Maked else tmpdepfile1=$dir$base.d tmpdepfile2=$dir$base.d "$@" +Maked fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" do test -f "$tmpdepfile" && break done if test -f "$tmpdepfile"; then sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile" # Add 'dependent.h:' lines. sed -ne '2,${ s/^ *// s/ \\*$// s/$/:/ p }' "$tmpdepfile" >> "$depfile" else make_dummy_depfile fi rm -f "$tmpdepfile" "$tmpdepfile2" ;; tru64) # The Tru64 compiler uses -MD to generate dependencies as a side # effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'. # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put # dependencies in 'foo.d' instead, so we check for that too. # Subdirectories are respected. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then # Libtool generates 2 separate objects for the 2 libraries. These # two compilations output dependencies in $dir.libs/$base.o.d and # in $dir$base.o.d. We have to check for both files, because # one of the two compilations can be disabled. We should prefer # $dir$base.o.d over $dir.libs/$base.o.d because the latter is # automatically cleaned when .libs/ is deleted, while ignoring # the former would cause a distcleancheck panic. tmpdepfile1=$dir$base.o.d # libtool 1.5 tmpdepfile2=$dir.libs/$base.o.d # Likewise. tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504 "$@" -Wc,-MD else tmpdepfile1=$dir$base.d tmpdepfile2=$dir$base.d tmpdepfile3=$dir$base.d "$@" -MD fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" do test -f "$tmpdepfile" && break done # Same post-processing that is required for AIX mode. aix_post_process_depfile ;; msvc7) if test "$libtool" = yes; then showIncludes=-Wc,-showIncludes else showIncludes=-showIncludes fi "$@" $showIncludes > "$tmpdepfile" stat=$? grep -v '^Note: including file: ' "$tmpdepfile" if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" # The first sed program below extracts the file names and escapes # backslashes for cygpath. The second sed program outputs the file # name when reading, but also accumulates all include files in the # hold buffer in order to output them again at the end. This only # works with sed implementations that can handle large buffers. sed < "$tmpdepfile" -n ' /^Note: including file: *\(.*\)/ { s//\1/ s/\\/\\\\/g p }' | $cygpath_u | sort -u | sed -n ' s/ /\\ /g s/\(.*\)/'"$tab"'\1 \\/p s/.\(.*\) \\/\1:/ H $ { s/.*/'"$tab"'/ G p }' >> "$depfile" echo >> "$depfile" # make sure the fragment doesn't end with a backslash rm -f "$tmpdepfile" ;; msvc7msys) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; #nosideeffect) # This comment above is used by automake to tell side-effect # dependency tracking mechanisms from slower ones. dashmstdout) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout, regardless of -o. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # Remove '-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done test -z "$dashmflag" && dashmflag=-M # Require at least two characters before searching for ':' # in the target name. This is to cope with DOS-style filenames: # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise. "$@" $dashmflag | sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile" rm -f "$depfile" cat < "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process this sed invocation # correctly. Breaking it into two sed invocations is a workaround. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; dashXmstdout) # This case only exists to satisfy depend.m4. It is never actually # run, as this mode is specially recognized in the preamble. exit 1 ;; makedepend) "$@" || exit $? # Remove any Libtool call if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # X makedepend shift cleared=no eat=no for arg do case $cleared in no) set ""; shift cleared=yes ;; esac if test $eat = yes; then eat=no continue fi case "$arg" in -D*|-I*) set fnord "$@" "$arg"; shift ;; # Strip any option that makedepend may not understand. Remove # the object too, otherwise makedepend will parse it as a source file. -arch) eat=yes ;; -*|$object) ;; *) set fnord "$@" "$arg"; shift ;; esac done obj_suffix=`echo "$object" | sed 's/^.*\././'` touch "$tmpdepfile" ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" rm -f "$depfile" # makedepend may prepend the VPATH from the source file name to the object. # No need to regex-escape $object, excess matching of '.' is harmless. sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process the last invocation # correctly. Breaking it into two sed invocations is a workaround. sed '1,2d' "$tmpdepfile" \ | tr ' ' "$nl" \ | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" "$tmpdepfile".bak ;; cpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # Remove '-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done "$@" -E \ | sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ | sed '$ s: \\$::' > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" cat < "$tmpdepfile" >> "$depfile" sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; msvisualcpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi IFS=" " for arg do case "$arg" in -o) shift ;; $object) shift ;; "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") set fnord "$@" shift shift ;; *) set fnord "$@" "$arg" shift shift ;; esac done "$@" -E 2>/dev/null | sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile" echo "$tab" >> "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile" rm -f "$tmpdepfile" ;; msvcmsys) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; none) exec "$@" ;; *) echo "Unknown depmode $depmode" 1>&2 exit 1 ;; esac exit 0 # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: partclone-0.2.86/docs/000077500000000000000000000000001262102574200145275ustar00rootroot00000000000000partclone-0.2.86/docs/Makefile.am000066400000000000000000000044201262102574200165630ustar00rootroot00000000000000XSLTPROC=xsltproc MAN_STYLESHEET=/usr/share/xml/docbook/stylesheet/docbook-xsl/manpages/docbook.xsl man_MANS = partclone.info.8 partclone.chkimg.8 partclone.dd.8 partclone.restore.8 partclone.8 partclone.imager.8 if ENABLE_EXTFS man_MANS += partclone.extfs.8 man_MANS += partclone.ext2.8 man_MANS += partclone.ext3.8 man_MANS += partclone.ext4.8 man_MANS += partclone.ext4dev.8 endif if ENABLE_REISERFS man_MANS += partclone.reiserfs.8 endif if ENABLE_REISER4 man_MANS += partclone.reiser4.8 endif if ENABLE_HFSP man_MANS += partclone.hfsplus.8 man_MANS += partclone.hfs+.8 man_MANS += partclone.hfsp.8 endif if ENABLE_XFS man_MANS += partclone.xfs.8 endif if ENABLE_F2FS man_MANS += partclone.f2fs.8 endif if ENABLE_NILFS2 man_MANS += partclone.nilfs2.8 endif if ENABLE_EXFAT man_MANS += partclone.exfat.8 endif if ENABLE_FAT man_MANS += partclone.fat.8 man_MANS += partclone.vfat.8 man_MANS += partclone.fat12.8 man_MANS += partclone.fat16.8 man_MANS += partclone.fat32.8 endif if ENABLE_UFS man_MANS += partclone.ufs.8 endif if ENABLE_VMFS man_MANS += partclone.vmfs.8 man_MANS += partclone.vmfs3.8 man_MANS += partclone.vmfs5.8 man_MANS += partclone.VMFS_volume_member.8 man_MANS += partclone.fstype.8 endif if ENABLE_JFS man_MANS += partclone.jfs.8 endif if ENABLE_BTRFS man_MANS += partclone.btrfs.8 endif if ENABLE_NTFS man_MANS += partclone.ntfs.8 man_MANS += partclone.ntfsfixboot.8 man_MANS += partclone.ntfsreloc.8 endif if ENABLE_MINIX man_MANS += partclone.minix.8 endif partclone.imager.8: partclone.imager.xml -@($(XSLTPROC) --nonet $(MAN_STYLESHEET) partclone.imager.xml) partclone.dd.8: partclone.dd.xml -@($(XSLTPROC) --nonet $(MAN_STYLESHEET) partclone.dd.xml) partclone.chkimg.8: partclone.chkimg.xml -@($(XSLTPROC) --nonet $(MAN_STYLESHEET) partclone.chkimg.xml) partclone.info.8: partclone.info.xml -@($(XSLTPROC) --nonet $(MAN_STYLESHEET) partclone.info.xml) partclone.restore.8: partclone.restore.xml -@($(XSLTPROC) --nonet $(MAN_STYLESHEET) partclone.restore.xml) partclone.8: partclone.xml -@($(XSLTPROC) --nonet $(MAN_STYLESHEET) partclone.xml) partclone.ntfsfixboot.8: partclone.ntfsfixboot.xml -@($(XSLTPROC) --nonet $(MAN_STYLESHEET) partclone.ntfsfixboot.xml) partclone.fstype.8: partclone.fstype.xml -@($(XSLTPROC) --nonet $(MAN_STYLESHEET) partclone.fstype.xml) partclone-0.2.86/docs/Makefile.in000066400000000000000000000426371262102574200166100ustar00rootroot00000000000000# Makefile.in generated by automake 1.15 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2014 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ @ENABLE_EXTFS_TRUE@am__append_1 = partclone.extfs.8 partclone.ext2.8 \ @ENABLE_EXTFS_TRUE@ partclone.ext3.8 partclone.ext4.8 \ @ENABLE_EXTFS_TRUE@ partclone.ext4dev.8 @ENABLE_REISERFS_TRUE@am__append_2 = partclone.reiserfs.8 @ENABLE_REISER4_TRUE@am__append_3 = partclone.reiser4.8 @ENABLE_HFSP_TRUE@am__append_4 = partclone.hfsplus.8 partclone.hfs+.8 \ @ENABLE_HFSP_TRUE@ partclone.hfsp.8 @ENABLE_XFS_TRUE@am__append_5 = partclone.xfs.8 @ENABLE_F2FS_TRUE@am__append_6 = partclone.f2fs.8 @ENABLE_NILFS2_TRUE@am__append_7 = partclone.nilfs2.8 @ENABLE_EXFAT_TRUE@am__append_8 = partclone.exfat.8 @ENABLE_FAT_TRUE@am__append_9 = partclone.fat.8 partclone.vfat.8 \ @ENABLE_FAT_TRUE@ partclone.fat12.8 partclone.fat16.8 \ @ENABLE_FAT_TRUE@ partclone.fat32.8 @ENABLE_UFS_TRUE@am__append_10 = partclone.ufs.8 @ENABLE_VMFS_TRUE@am__append_11 = partclone.vmfs.8 partclone.vmfs3.8 \ @ENABLE_VMFS_TRUE@ partclone.vmfs5.8 \ @ENABLE_VMFS_TRUE@ partclone.VMFS_volume_member.8 \ @ENABLE_VMFS_TRUE@ partclone.fstype.8 @ENABLE_JFS_TRUE@am__append_12 = partclone.jfs.8 @ENABLE_BTRFS_TRUE@am__append_13 = partclone.btrfs.8 @ENABLE_NTFS_TRUE@am__append_14 = partclone.ntfs.8 \ @ENABLE_NTFS_TRUE@ partclone.ntfsfixboot.8 \ @ENABLE_NTFS_TRUE@ partclone.ntfsreloc.8 @ENABLE_MINIX_TRUE@am__append_15 = partclone.minix.8 subdir = docs ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/gettext.m4 \ $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } man8dir = $(mandir)/man8 am__installdirs = "$(DESTDIR)$(man8dir)" NROFF = nroff MANS = $(man_MANS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__DIST_COMMON = $(srcdir)/Makefile.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXT2FS_CFLAGS = @EXT2FS_CFLAGS@ EXT2FS_LIBS = @EXT2FS_LIBS@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ LDFLAGS = @LDFLAGS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LN_S = @LN_S@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ NTFS_CFLAGS = @NTFS_CFLAGS@ NTFS_LIBS = @NTFS_LIBS@ OBJEXT = @OBJEXT@ ORIGINAL_CFLAGS = @ORIGINAL_CFLAGS@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ POSUB = @POSUB@ RM = @RM@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ USE_NLS = @USE_NLS@ UUID_CFLAGS = @UUID_CFLAGS@ UUID_LIBS = @UUID_LIBS@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ XSLTPROC = xsltproc MAN_STYLESHEET = /usr/share/xml/docbook/stylesheet/docbook-xsl/manpages/docbook.xsl man_MANS = partclone.info.8 partclone.chkimg.8 partclone.dd.8 \ partclone.restore.8 partclone.8 partclone.imager.8 \ $(am__append_1) $(am__append_2) $(am__append_3) \ $(am__append_4) $(am__append_5) $(am__append_6) \ $(am__append_7) $(am__append_8) $(am__append_9) \ $(am__append_10) $(am__append_11) $(am__append_12) \ $(am__append_13) $(am__append_14) $(am__append_15) all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign docs/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign docs/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-man8: $(man_MANS) @$(NORMAL_INSTALL) @list1=''; \ list2='$(man_MANS)'; \ test -n "$(man8dir)" \ && test -n "`echo $$list1$$list2`" \ || exit 0; \ echo " $(MKDIR_P) '$(DESTDIR)$(man8dir)'"; \ $(MKDIR_P) "$(DESTDIR)$(man8dir)" || exit 1; \ { for i in $$list1; do echo "$$i"; done; \ if test -n "$$list2"; then \ for i in $$list2; do echo "$$i"; done \ | sed -n '/\.8[a-z]*$$/p'; \ fi; \ } | while read p; do \ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; echo "$$p"; \ done | \ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^8][0-9a-z]*$$,8,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ sed 'N;N;s,\n, ,g' | { \ list=; while read file base inst; do \ if test "$$base" = "$$inst"; then list="$$list $$file"; else \ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man8dir)/$$inst'"; \ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man8dir)/$$inst" || exit $$?; \ fi; \ done; \ for i in $$list; do echo "$$i"; done | $(am__base_list) | \ while read files; do \ test -z "$$files" || { \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man8dir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(man8dir)" || exit $$?; }; \ done; } uninstall-man8: @$(NORMAL_UNINSTALL) @list=''; test -n "$(man8dir)" || exit 0; \ files=`{ for i in $$list; do echo "$$i"; done; \ l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \ sed -n '/\.8[a-z]*$$/p'; \ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^8][0-9a-z]*$$,8,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ dir='$(DESTDIR)$(man8dir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(MANS) installdirs: for dir in "$(DESTDIR)$(man8dir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-man install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-man8 install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-man uninstall-man: uninstall-man8 .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic cscopelist-am \ ctags-am distclean distclean-generic distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-man8 install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic pdf \ pdf-am ps ps-am tags-am uninstall uninstall-am uninstall-man \ uninstall-man8 .PRECIOUS: Makefile partclone.imager.8: partclone.imager.xml -@($(XSLTPROC) --nonet $(MAN_STYLESHEET) partclone.imager.xml) partclone.dd.8: partclone.dd.xml -@($(XSLTPROC) --nonet $(MAN_STYLESHEET) partclone.dd.xml) partclone.chkimg.8: partclone.chkimg.xml -@($(XSLTPROC) --nonet $(MAN_STYLESHEET) partclone.chkimg.xml) partclone.info.8: partclone.info.xml -@($(XSLTPROC) --nonet $(MAN_STYLESHEET) partclone.info.xml) partclone.restore.8: partclone.restore.xml -@($(XSLTPROC) --nonet $(MAN_STYLESHEET) partclone.restore.xml) partclone.8: partclone.xml -@($(XSLTPROC) --nonet $(MAN_STYLESHEET) partclone.xml) partclone.ntfsfixboot.8: partclone.ntfsfixboot.xml -@($(XSLTPROC) --nonet $(MAN_STYLESHEET) partclone.ntfsfixboot.xml) partclone.fstype.8: partclone.fstype.xml -@($(XSLTPROC) --nonet $(MAN_STYLESHEET) partclone.fstype.xml) # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: partclone-0.2.86/docs/partclone.8000066400000000000000000000203551262102574200166140ustar00rootroot00000000000000'\" t .\" Title: PARTCLONE .\" Author: Yu-Chin Tsai .\" Generator: DocBook XSL Stylesheets v1.78.1 .\" Date: 11/04/2015 .\" Manual: Partclone User Manual .\" Source: partclone .\" Language: English .\" .TH "PARTCLONE" "8" "11/04/2015" "partclone" "Partclone User Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" partclone \- The utility for clone and restore a partition\&. .SH "SYNOPSIS" .HP \w'\fBpartclone\&.[fstype]\fR\ 'u \fBpartclone\&.[fstype]\fR {[\fB\-c\fR\ |\ \fB\-\-clone\fR]\ [\fB\-r\fR\ |\ \fB\-\-restore\fR]\ [\fB\-b\fR\ |\ \fB\-\-dev\-to\-dev\fR]} {[\fB\-s\fR\ |\ \fB\-\-source\fR]\ \fIsource\fR} {[[\fB\-o\fR\ |\ \fB\-\-output\fR]\ [\fB\-O\fR\ |\ \fB\-\-overwrite\fR]]\ \fItarget\fR} [[\fB\-dX\fR\ |\ \fB\-\-debug=X\fR]\ [\fB\-\-restore_raw_file\fR]] [[\fB\-z\fR\ |\ \fB\-\-buffer_size\fR]\ [\fB\-N\fR\ |\ \fB\-\-ncurses\fR]] [[\fB\-q\fR\ |\ \fB\-\-quiet\fR]\ [\fB\-f\fR\ |\ \fB\-\-UI\-fresh\fR]] [[\fB\-F\fR\ |\ \fB\-\-force\fR]\ [\fB\-I\fR\ |\ \fB\-\-ignore_fschk\fR]] [[\fB\-\-ignore_crc\fR]\ [\fB\-X\fR\ |\ \fB\-\-dialog\fR]\ [\fB\-C\fR\ |\ \fB\-\-nocheck\fR]] [[\fB\-R\fR\ |\ \fB\-\-rescue\fR]\ [\fB\-L\fR\ |\ \fB\-\-logfile\fR]\ \fIlogfile\fR] .SH "DESCRIPTION" .PP \fBpartclone\fR\&.[fstype] is a part of \fBPartclone\fR project\&. Partclone provide utilities to backup used blocks and design for higher compatibility of the file system by using existing library, e\&.g\&. e2fslibs is used to read the used block of ext2 partition\&. .PP \fBPartclone\fR supported file system include btrfs, ext2, ext3, ext4, reiserfs, reiser4, xfs and jfs for LINUX\&. Also support some non\-linux operation system, ex: NTFS, FAT and EXFAT(for Windows), HFS plus(APPLE MAC OS), UFS2(FreeBSD), VMFS(VMWare Vsphere) and MINIX(MINIX3)\&. .PP All partclone utils could be run like partclone\&.[fstype] is very smiliar fsck or mkfs\&. For example, for backup/restore hfsplus, just run partclone\&.hfsp .sp .if n \{\ .RS 4 .\} .nf File System partclone\&.[fstype] btrfs partclone\&.btrfs ext2, ext3, ext4 partclone\&.[ext2|ext3|ext4] reiserfs 3\&.5 partclone\&.reiserfs reiser 4 partclone\&.reiser4 xfs partclone\&.xfs ufs | ufs2 partclone\&.ufs jfs partclone\&.jfs hfs plusfs partclone\&.[hfs+|hfsplus] vmfs partclone\&.vmfs ntfs partclone\&.ntfs fat12, fat16, fat32 partclone\&.[fat12|fat16|fat32] exfat partclone\&.exfat minix partclone\&.minix f2fs partclone\&.f2fs .fi .if n \{\ .RE .\} .SH "OPTIONS" .PP The program follows the usual GNU command line syntax, with long options starting with two dashes (`\-\*(Aq)\&. A summary of options is included below\&. .PP \fB\-s \fR\fB\fIFILE\fR\fR, \fB\-\-source \fR\fB\fIFILE\fR\fR .RS 4 Source FILE\&. The FILE could be a image file(made by partclone) or device depend on your action\&. Normanly, backup source is device, restore source is image file\&. .sp Receving data from pipe line is supported ONLY for restoring, just ignore \-s option or use \*(Aq\-\*(Aq means receive data from stdin\&. .RE .PP \fB\-o \fR\fB\fIFILE\fR\fR, \fB\-\-output \fR\fB\fIFILE\fR\fR .RS 4 Output FILE\&. The FILE could be a image file(partclone will generate) or device depend on your action\&. Normanly, backup output to image file and restore output to device\&. .sp Sending data to pipe line is also supported ONLY for back\-up, just ignore \-o option or use \*(Aq\-\*(Aq means send data to stdout\&. .RE .PP \fB\-O \fR\fB\fIFILE\fR\fR, \fB\-\-overwrite \fR\fB\fIFILE\fR\fR .RS 4 Overwrite FILE, overwriting if exists\&. .RE .PP \fB\-c\fR, \fB\-\-clone\fR .RS 4 Save partition to the special image format\&. .RE .PP \fB\-r\fR, \fB\-\-restore\fR .RS 4 Restore partition from the special image format\&. .RE .PP \fB\-b\fR, \fB\-\-dev\-to\-dev\fR .RS 4 Local device to device copy on\-the\-fly, source and output both are device\&. .RE .PP \fB\-D\fR, \fB\-\-domain\fR .RS 4 Create GNU Ddrescue domain log file from source device .RE .PP \fB\-\-offset_domain=X\fR .RS 4 Add X (in bytes) to all positions reported in the domain log file .RE .PP \fB\-\-restore_raw_file\fR .RS 4 Creating special raw file for loop device\&. .RE .PP \fB\-l \fR\fB\fIFILE\fR\fR, \fB\-\-logfile \fR\fB\fIFILE\fR\fR .RS 4 put special path to record partclone log information\&.(default /var/log/partclone\&.log) .RE .PP \fB\-R\fR, \fB\-\-rescue\fR .RS 4 Continue after disk read errors\&. .RE .PP \fB\-C\fR, \fB\-\-no_check\fR .RS 4 Don\*(Aqt check device size and free space\&. .RE .PP \fB\-N\fR, \fB\-\-ncurse\fR .RS 4 Using Ncurses Text User Interface\&. .RE .PP \fB\-X\fR, \fB\-\-dialog\fR .RS 4 Output message as Dialog Format\&. .RE .PP \fB\-I\fR, \fB\-\-ignore_fschk\fR .RS 4 Ignore filesystem check\&. .RE .PP \fB\-\-ignore_crc\fR .RS 4 Ignore crc check error\&. .RE .PP \fB\-F\fR, \fB\-\-force\fR .RS 4 Force progress\&. .RE .PP \fB\-f \fR\fB\fIsec\fR\fR, \fB\-\-UI\-fresh \fR\fB\fIsec\fR\fR .RS 4 put special second to different interval\&. .RE .PP \fB\-z \fR\fB\fIsize\fR\fR, \fB\-\-buffer_size \fR\fB\fIsize\fR\fR .RS 4 Read/write buffer size (default: 1048576) .RE .PP \fB\-q\fR, \fB\-\-quiet\fR .RS 4 Disable progress message\&. .RE .PP \fB\-d\fR\fB\fIlevel\fR\fR, \fB\-\-debug \fR\fB\fIlevel\fR\fR .RS 4 Set the debug level [1|2|3] .RE .PP \fB\-h\fR, \fB\-\-help\fR .RS 4 Show summary of options\&. .RE .PP \fB\-v\fR, \fB\-\-version\fR .RS 4 Show version of program\&. .RE .SH "FILES" .PP /var/log/partclone\&.log .RS 4 The log file of partclone .RE .SH "EXAMPLES" .sp .if n \{\ .RS 4 .\} .nf clone /dev/hda1 to hda1\&.img and display debug information\&. partclone\&.ext3 \-c \-d \-s /dev/hda1 \-o hda1\&.img restore /dev/hda1 from hda1\&.img and display debug information\&. partclone\&.extfs \-r \-d \-s hda1\&.img \-o /dev/hda1 restore image from clonezilla(split, gzip,) with stdin source cat sda1\&.ext3\-ptcl\-img\&.gz\&.a* | gunzip \-c | partclone\&.ext3 \-d \-r \-s \- \-o /dev/sda1 .fi .if n \{\ .RE .\} .SH "DIAGNOSTICS" .PP The following diagnostics may be issued on stderr: .PP \fBpartclone\fR provides some return codes, that can be used in scripts: .\" line length increase to cope w/ tbl weirdness .ll +(\n(LLu * 62u / 100u) .TS ll. \fICode\fR \fIDiagnostic\fR T{ \fB0\fR T} T{ Program exited successfully\&. T} T{ \fB1\fR T} T{ Clone or Restore seem failed\&. T} .TE .\" line length decrease back to previous value .ll -(\n(LLu * 62u / 100u) .sp .SH "BUGS" .PP Report bugs to thomas@nchc\&.org\&.tw or \m[blue]\fB\%http://partclone.org\fR\m[]\&. .PP You can get support at http://partclone\&.org .SH "SEE ALSO" .PP \fBpartclone\fR(8), \fBpartclone.chkimg\fR(8), \fBpartclone.restore\fR(8), \fBpartclone.dd\fR(8), \fBpartclone.info\fR(8) .SH "AUTHOR" .PP \fBYu\-Chin Tsai\fR <\&thomas@nchc\&.org\&.tw\&> .RS 4 .RE .SH "COPYRIGHT" .br Copyright \(co 2007 Yu-Chin Tsai .br .PP This manual page was written for the Debian system (and may be used by others)\&. .PP Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 2 or (at your option) any later version published by the Free Software Foundation\&. .PP On Debian systems, the complete text of the GNU General Public License can be found in /usr/share/common\-licenses/GPL\&. .sp partclone-0.2.86/docs/partclone.VMFS_volume_member.8000066400000000000000000000000251262102574200222740ustar00rootroot00000000000000.so man8/partclone.8 partclone-0.2.86/docs/partclone.btrfs.8000066400000000000000000000000251262102574200177230ustar00rootroot00000000000000.so man8/partclone.8 partclone-0.2.86/docs/partclone.chkimg.8000066400000000000000000000125631262102574200200570ustar00rootroot00000000000000'\" t .\" Title: PARTCLONE.CHKIMG .\" Author: Yu-Chin Tsai .\" Generator: DocBook XSL Stylesheets v1.78.1 .\" Date: 09/19/2015 .\" Manual: Partclone User Manual .\" Source: partclone.chkimg .\" Language: English .\" .TH "PARTCLONE\&.CHKIMG" "8" "09/19/2015" "partclone.chkimg" "Partclone User Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" partclone.chkimg \- The utility to check image made by partclone .SH "SYNOPSIS" .HP \w'\fBpartclone\&.chkimg\fR\ 'u \fBpartclone\&.chkimg\fR {[\fB\-s\fR\ |\ \fB\-\-source\fR]\ \fIsource\fR} [[\fB\-dX\fR\ |\ \fB\-\-debug=X\fR]\ [\fB\-N\fR\ |\ \fB\-\-ncurses\fR]\ [\fB\-f\fR\ |\ \fB\-\-UI\-fresh\fR]\ [\fB\-F\fR\ |\ \fB\-\-force\fR]\ [\fB\-\-ignore_crc\fR]\ [\fB\-X\fR\ |\ \fB\-\-dialog\fR]\ [\fB\-C\fR\ |\ \fB\-\-no_check\fR]\ [\fB\-L\fR\ |\ \fB\-\-logfile\fR]\ \fIlogfile\fR] .SH "DESCRIPTION" .PP \fBpartclone\&.chkimg\fR is a part of \fBPartclone\fR project to veritfy image file\&. Partclone provide utilities to backup used blocks and design for higher compatibility of the file system by using existing library, e\&.g\&. e2fslibs is used to read the used block of ext2 partition\&. .PP \fBPartclone\fR supported file system include btrfs, ext2, ext3, ext4, reiserfs, reiser4, xfs and jfs for LINUX\&. Also support some non\-linux operation system, ex: NTFS, FAT, EXFAT(for Windows), HFS plus(APPLE MAC OS), UFS2(FreeBSD), VMFS(VMWare Vsphere)\&. All partclone utils could be run like partclone\&.xxx is very smiliar fsck or mkfs\&. For example, for backup/restore hfsplus, just run partclone\&.hfsp\&. .SH "OPTIONS" .PP The program follows the usual GNU command line syntax, with long options starting with two dashes (`\-\*(Aq)\&. A summary of options is included below\&. .PP \fB\-s \fR\fB\fIFILE\fR\fR, \fB\-\-source \fR\fB\fIFILE\fR\fR .RS 4 Source FILE\&. The FILE could be a image file(made by partclone) or device depend on your action\&. Normanly, backup source is device, restore source is image file\&. .sp Receving data from pipe line is supported ONLY for restoring, just ignore \-s option or use \*(Aq\-\*(Aq means receive data from stdin\&. .RE .PP \fB\-l \fR\fB\fIFILE\fR\fR, \fB\-\-logfile \fR\fB\fIFILE\fR\fR .RS 4 put special path to record partclone log information\&.(default /var/log/partclone\&.log) .RE .PP \fB\-C\fR, \fB\-\-no_check\fR .RS 4 Don\*(Aqt check device size and free space\&. .RE .PP \fB\-N\fR, \fB\-\-ncurse\fR .RS 4 Using Ncurses Text User Interface\&. .RE .PP \fB\-X\fR, \fB\-\-dialog\fR .RS 4 Output message as Dialog Format\&. .RE .PP \fB\-\-ignore_crc\fR .RS 4 Ignore crc check error\&. .RE .PP \fB\-F\fR, \fB\-\-force\fR .RS 4 Force progress\&. .RE .PP \fB\-f \fR\fB\fIsec\fR\fR, \fB\-\-UI\-fresh \fR\fB\fIsec\fR\fR .RS 4 put special second to different interval\&. .RE .PP \fB\-d\fR\fB\fIlevel\fR\fR, \fB\-\-debug \fR\fB\fIlevel\fR\fR .RS 4 Set the debug level [1|2|3] .RE .PP \fB\-h\fR, \fB\-\-help\fR .RS 4 Show summary of options\&. .RE .PP \fB\-v\fR, \fB\-\-version\fR .RS 4 Show version of program\&. .RE .SH "FILES" .PP /var/log/partclone\&.log .RS 4 The log file of partclone\&.chkimg .RE .SH "EXAMPLES" .sp .if n \{\ .RS 4 .\} .nf check part\&.img file is correct or not\&. partclone\&.chkimg \-d \-s partclone\&.img .fi .if n \{\ .RE .\} .SH "DIAGNOSTICS" .PP The following diagnostics may be issued on stderr: .PP \fBpartclone\&.chkimg\fR provides some return codes, that can be used in scripts: .\" line length increase to cope w/ tbl weirdness .ll +(\n(LLu * 62u / 100u) .TS ll. \fICode\fR \fIDiagnostic\fR T{ \fB0\fR T} T{ Program exited successfully\&. T} T{ \fB1\fR T} T{ Clone or Restore seem failed\&. T} .TE .\" line length decrease back to previous value .ll -(\n(LLu * 62u / 100u) .sp .SH "BUGS" .PP Report bugs to thomas@nchc\&.org\&.tw or \m[blue]\fB\%http://partclone.org\fR\m[]\&. .PP You can get support at http://partclone\&.org .SH "SEE ALSO" .PP \fBpartclone\fR(8), \fBpartclone.chkimg\fR(8), \fBpartclone.restore\fR(8), \fBpartclone.dd\fR(8), \fBpartclone.info\fR(8) .SH "AUTHOR" .PP \fBYu\-Chin Tsai\fR <\&thomas@nchc\&.org\&.tw\&> .RS 4 .RE .SH "COPYRIGHT" .br Copyright \(co 2007 Yu-Chin Tsai .br .PP This manual page was written for the Debian system (and may be used by others)\&. .PP Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 2 or (at your option) any later version published by the Free Software Foundation\&. .PP On Debian systems, the complete text of the GNU General Public License can be found in /usr/share/common\-licenses/GPL\&. .sp partclone-0.2.86/docs/partclone.chkimg.xml000066400000000000000000000273171262102574200205130ustar00rootroot00000000000000 .
will be generated. You may view the manual page with: nroff -man .
| less'. A typical entry in a Makefile or Makefile.am is: DB2MAN = /usr/share/sgml/docbookstylesheet/xsl/docbook-xsl/manpages/docbook.xsl XP = xsltproc -''-nonet -''-param man.charmap.use.subset "0" manpage.1: manpage.xml $(XP) $(DB2MAN) $< The xsltproc binary is found in the xsltproc package. The XSL files are in docbook-xsl. A description of the parameters you can use can be found in the docbook-xsl-doc-* packages. Please remember that if you create the nroff version in one of the debian/rules file targets (such as build), you will need to include xsltproc and docbook-xsl in your Build-Depends control field. Alternatively use the xmlto command/package. That will also automatically pull in xsltproc and docbook-xsl. Notes for using docbook2x: docbook2x-man does not automatically create the AUTHOR(S) and COPYRIGHT sections. In this case, please add them manually as ... . To disable the automatic creation of the AUTHOR(S) and COPYRIGHT sections read /usr/share/doc/docbook-xsl/doc/manpages/authors.html. This file can be found in the docbook-xsl-doc-html package. Validation can be done using: `xmllint -''-noout -''-valid manpage.xml` General documentation about man-pages and man-page-formatting: man(1), man(7), http://www.tldp.org/HOWTO/Man-Page/ --> ]> &dhtitle; &dhpackage; &dhfirstname; &dhsurname;
&dhemail;
2007 &dhusername; This manual page was written for the Debian system (and may be used by others). Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 2 or (at your option) any later version published by the Free Software Foundation. On Debian systems, the complete text of the GNU General Public License can be found in /usr/share/common-licenses/GPL.
&dhucpackage; &dhsection; &dhpackage; The utility to check image made by partclone &dhpackage; source logfile DESCRIPTION &dhpackage; is a part of Partclone project to veritfy image file. Partclone provide utilities to backup used blocks and design for higher compatibility of the file system by using existing library, e.g. e2fslibs is used to read the used block of ext2 partition. Partclone supported file system include btrfs, ext2, ext3, ext4, reiserfs, reiser4, xfs and jfs for LINUX. Also support some non-linux operation system, ex: NTFS, FAT, EXFAT(for Windows), HFS plus(APPLE MAC OS), UFS2(FreeBSD), VMFS(VMWare Vsphere). All partclone utils could be run like partclone.xxx is very smiliar fsck or mkfs. For example, for backup/restore hfsplus, just run partclone.hfsp. OPTIONS The program follows the usual GNU command line syntax, with long options starting with two dashes (`-'). A summary of options is included below. Source FILE. The FILE could be a image file(made by partclone) or device depend on your action. Normanly, backup source is device, restore source is image file. Receving data from pipe line is supported ONLY for restoring, just ignore -s option or use '-' means receive data from stdin. put special path to record partclone log information.(default /var/log/partclone.log) Don't check device size and free space. Using Ncurses Text User Interface. Output message as Dialog Format. Ignore crc check error. Force progress. put special second to different interval. Set the debug level [1|2|3] Show summary of options. Show version of program. FILES /var/log/partclone.log The log file of &dhpackage; EXAMPLES check part.img file is correct or not. partclone.chkimg -d -s partclone.img DIAGNOSTICS The following diagnostics may be issued on stderr: &dhpackage; provides some return codes, that can be used in scripts: Code Diagnostic 0 Program exited successfully. 1 Clone or Restore seem failed. BUGS Report bugs to &dhemail; or . You can get support at http://partclone.org SEE ALSO partclone 8 , partclone.chkimg 8 , partclone.restore 8 , partclone.dd 8 , partclone.info 8
partclone-0.2.86/docs/partclone.dd.8000066400000000000000000000153571262102574200172100ustar00rootroot00000000000000'\" t .\" Title: PARTCLONE.DD .\" Author: Yu-Chin Tsai .\" Generator: DocBook XSL Stylesheets v1.78.1 .\" Date: 09/19/2015 .\" Manual: Partclone User Manual .\" Source: partclone.dd .\" Language: English .\" .TH "PARTCLONE\&.DD" "8" "09/19/2015" "partclone.dd" "Partclone User Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" partclone.dd \- unsupported file system backup utility\&.(like `dd` ) .SH "SYNOPSIS" .HP \w'\fBpartclone\&.dd\fR\ 'u \fBpartclone\&.dd\fR {[\fB\-s\fR\ |\ \fB\-\-source\fR]\ \fIsource\fR} {[[\fB\-o\fR\ |\ \fB\-\-output\fR]\ [\fB\-O\fR\ |\ \fB\-\-overwrite\fR]]\ \fItarget\fR} [[\fB\-dX\fR\ |\ \fB\-\-debug=X\fR]\ [\fB\-\-restore_raw_file\fR]\ [\fB\-z\fR\ |\ \fB\-\-buffer_size\fR]\ [\fB\-N\fR\ |\ \fB\-\-ncurses\fR]\ [\fB\-q\fR\ |\ \fB\-\-quiet\fR]\ [\fB\-f\fR\ |\ \fB\-\-UI\-fresh\fR]\ [\fB\-F\fR\ |\ \fB\-\-force\fR]\ [\fB\-I\fR\ |\ \fB\-\-ignore_fschk\fR]\ [\fB\-\-ignore_crc\fR]\ [\fB\-X\fR\ |\ \fB\-\-dialog\fR]\ [\fB\-C\fR\ |\ \fB\-\-nocheck\fR]\ [\fB\-R\fR\ |\ \fB\-\-rescue\fR]\ [\fB\-L\fR\ |\ \fB\-\-logfile\fR]\ \fIlogfile\fR] .SH "DESCRIPTION" .PP \fBpartclone\&.dd\fR is a part of \fBPartclone\fR project to clone unsupported file system with dd method\&. It will backup all block from partition\&. Partclone provide utilities to backup used blocks and design for higher compatibility of the file system by using existing library, e\&.g\&. e2fslibs is used to read the used block of ext2 partition\&. .PP \fBPartclone\fR supported file system include btrfs, ext2, ext3, ext4, reiserfs, reiser4, xfs and jfs for LINUX\&. Also support some non\-linux operation system, ex: NTFS and FAT (for Windows), HFS plus(APPLE MAC OS), UFS2(FreeBSD), VMFS(VMWare Vsphere)\&. All partclone utils could be run like partclone\&.xxx is very smiliar fsck or mkfs\&. For example, for backup/restore hfsplus, just run partclone\&.hfsp\&. .SH "OPTIONS" .PP The program follows the usual GNU command line syntax, with long options starting with two dashes (`\-\*(Aq)\&. A summary of options is included below\&. .PP \fB\-s \fR\fB\fIFILE\fR\fR, \fB\-\-source \fR\fB\fIFILE\fR\fR .RS 4 Source FILE\&. The FILE could be a image file(made by partclone) or device depend on your action\&. Normanly, backup source is device, restore source is image file\&. .sp Receving data from pipe line is supported ONLY for restoring, just ignore \-s option or use \*(Aq\-\*(Aq means receive data from stdin\&. .RE .PP \fB\-o \fR\fB\fIFILE\fR\fR, \fB\-\-output \fR\fB\fIFILE\fR\fR .RS 4 Output FILE\&. The FILE could be a image file(partclone will generate) or device depend on your action\&. Normanly, backup output to image file and restore output to device\&. .sp Sending data to pipe line is also supported ONLY for back\-up, just ignore \-o option or use \*(Aq\-\*(Aq means send data to stdout\&. .RE .PP \fB\-O \fR\fB\fIFILE\fR\fR, \fB\-\-overwrite \fR\fB\fIFILE\fR\fR .RS 4 Overwrite FILE, overwriting if exists\&. .RE .PP \fB\-\-restore_raw_file\fR .RS 4 Creating special raw file for loop device\&. .RE .PP \fB\-l \fR\fB\fIFILE\fR\fR, \fB\-\-logfile \fR\fB\fIFILE\fR\fR .RS 4 put special path to record partclone log information\&.(default /var/log/partclone\&.log) .RE .PP \fB\-R\fR, \fB\-\-rescue\fR .RS 4 Continue after disk read errors\&. .RE .PP \fB\-C\fR, \fB\-\-no_check\fR .RS 4 Don\*(Aqt check device size and free space\&. .RE .PP \fB\-N\fR, \fB\-\-ncurse\fR .RS 4 Using Ncurses Text User Interface\&. .RE .PP \fB\-X\fR, \fB\-\-dialog\fR .RS 4 Output message as Dialog Format\&. .RE .PP \fB\-I\fR, \fB\-\-ignore_fschk\fR .RS 4 Ignore filesystem check\&. .RE .PP \fB\-\-ignore_crc\fR .RS 4 Ignore crc check error\&. .RE .PP \fB\-F\fR, \fB\-\-force\fR .RS 4 Force progress\&. .RE .PP \fB\-f \fR\fB\fIsec\fR\fR, \fB\-\-UI\-fresh \fR\fB\fIsec\fR\fR .RS 4 put special second to different interval\&. .RE .PP \fB\-z \fR\fB\fIsize\fR\fR, \fB\-\-buffer_size \fR\fB\fIsize\fR\fR .RS 4 Read/write buffer size (default: 1048576) .RE .PP \fB\-q\fR, \fB\-\-quiet\fR .RS 4 Disable progress message\&. .RE .PP \fB\-d\fR\fB\fIlevel\fR\fR, \fB\-\-debug \fR\fB\fIlevel\fR\fR .RS 4 Set the debug level [1|2|3] .RE .PP \fB\-h\fR, \fB\-\-help\fR .RS 4 Show summary of options\&. .RE .PP \fB\-v\fR, \fB\-\-version\fR .RS 4 Show version of program\&. .RE .SH "FILES" .PP /var/log/partclone\&.log .RS 4 The log file of partclone\&.dd .RE .SH "EXAMPLES" .sp .if n \{\ .RS 4 .\} .nf clone /dev/hda1 to hda1\&.dd\&.img and display debug information\&. partclone\&.dd \-d \-s /dev/hda1 \-o hda1\&.dd\&.img restore /dev/hda1 from hda1\&.dd\&.img and display debug information\&. partclone\&.dd \-d \-s hda1\&.dd\&.img \-o /dev/hda1 .fi .if n \{\ .RE .\} .SH "DIAGNOSTICS" .PP The following diagnostics may be issued on stderr: .PP \fBpartclone\&.dd\fR provides some return codes, that can be used in scripts: .\" line length increase to cope w/ tbl weirdness .ll +(\n(LLu * 62u / 100u) .TS ll. \fICode\fR \fIDiagnostic\fR T{ \fB0\fR T} T{ Program exited successfully\&. T} T{ \fB1\fR T} T{ Clone or Restore seem failed\&. T} .TE .\" line length decrease back to previous value .ll -(\n(LLu * 62u / 100u) .sp .SH "BUGS" .PP Report bugs to thomas@nchc\&.org\&.tw or \m[blue]\fB\%http://partclone.org\fR\m[]\&. .PP You can get support at http://partclone\&.org .SH "SEE ALSO" .PP \fBpartclone\fR(8), \fBpartclone.chkimg\fR(8), \fBpartclone.restore\fR(8), \fBpartclone.dd\fR(8), \fBpartclone.info\fR(8) .SH "AUTHOR" .PP \fBYu\-Chin Tsai\fR <\&thomas@nchc\&.org\&.tw\&> .RS 4 .RE .SH "COPYRIGHT" .br Copyright \(co 2007 Yu-Chin Tsai .br .PP This manual page was written for the Debian system (and may be used by others)\&. .PP Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 2 or (at your option) any later version published by the Free Software Foundation\&. .PP On Debian systems, the complete text of the GNU General Public License can be found in /usr/share/common\-licenses/GPL\&. .sp partclone-0.2.86/docs/partclone.dd.xml000066400000000000000000000357171262102574200176430ustar00rootroot00000000000000 .
will be generated. You may view the manual page with: nroff -man .
| less'. A typical entry in a Makefile or Makefile.am is: DB2MAN = /usr/share/sgml/docbookstylesheet/xsl/docbook-xsl/manpages/docbook.xsl XP = xsltproc -''-nonet -''-param man.charmap.use.subset "0" manpage.1: manpage.xml $(XP) $(DB2MAN) $< The xsltproc binary is found in the xsltproc package. The XSL files are in docbook-xsl. A description of the parameters you can use can be found in the docbook-xsl-doc-* packages. Please remember that if you create the nroff version in one of the debian/rules file targets (such as build), you will need to include xsltproc and docbook-xsl in your Build-Depends control field. Alternatively use the xmlto command/package. That will also automatically pull in xsltproc and docbook-xsl. Notes for using docbook2x: docbook2x-man does not automatically create the AUTHOR(S) and COPYRIGHT sections. In this case, please add them manually as ... . To disable the automatic creation of the AUTHOR(S) and COPYRIGHT sections read /usr/share/doc/docbook-xsl/doc/manpages/authors.html. This file can be found in the docbook-xsl-doc-html package. Validation can be done using: `xmllint -''-noout -''-valid manpage.xml` General documentation about man-pages and man-page-formatting: man(1), man(7), http://www.tldp.org/HOWTO/Man-Page/ --> ]> &dhtitle; &dhpackage; &dhfirstname; &dhsurname;
&dhemail;
2007 &dhusername; This manual page was written for the Debian system (and may be used by others). Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 2 or (at your option) any later version published by the Free Software Foundation. On Debian systems, the complete text of the GNU General Public License can be found in /usr/share/common-licenses/GPL.
&dhucpackage; &dhsection; &dhpackage; unsupported file system backup utility.(like `dd` ) &dhpackage; source target logfile DESCRIPTION &dhpackage; is a part of Partclone project to clone unsupported file system with dd method. It will backup all block from partition. Partclone provide utilities to backup used blocks and design for higher compatibility of the file system by using existing library, e.g. e2fslibs is used to read the used block of ext2 partition. Partclone supported file system include btrfs, ext2, ext3, ext4, reiserfs, reiser4, xfs and jfs for LINUX. Also support some non-linux operation system, ex: NTFS and FAT (for Windows), HFS plus(APPLE MAC OS), UFS2(FreeBSD), VMFS(VMWare Vsphere). All partclone utils could be run like partclone.xxx is very smiliar fsck or mkfs. For example, for backup/restore hfsplus, just run partclone.hfsp. OPTIONS The program follows the usual GNU command line syntax, with long options starting with two dashes (`-'). A summary of options is included below. Source FILE. The FILE could be a image file(made by partclone) or device depend on your action. Normanly, backup source is device, restore source is image file. Receving data from pipe line is supported ONLY for restoring, just ignore -s option or use '-' means receive data from stdin. Output FILE. The FILE could be a image file(partclone will generate) or device depend on your action. Normanly, backup output to image file and restore output to device. Sending data to pipe line is also supported ONLY for back-up, just ignore -o option or use '-' means send data to stdout. Overwrite FILE, overwriting if exists. Creating special raw file for loop device. put special path to record partclone log information.(default /var/log/partclone.log) Continue after disk read errors. Don't check device size and free space. Using Ncurses Text User Interface. Output message as Dialog Format. Ignore filesystem check. Ignore crc check error. Force progress. put special second to different interval. Read/write buffer size (default: 1048576) Disable progress message. Set the debug level [1|2|3] Show summary of options. Show version of program. FILES /var/log/partclone.log The log file of &dhpackage; EXAMPLES clone /dev/hda1 to hda1.dd.img and display debug information. partclone.dd -d -s /dev/hda1 -o hda1.dd.img restore /dev/hda1 from hda1.dd.img and display debug information. partclone.dd -d -s hda1.dd.img -o /dev/hda1 DIAGNOSTICS The following diagnostics may be issued on stderr: &dhpackage; provides some return codes, that can be used in scripts: Code Diagnostic 0 Program exited successfully. 1 Clone or Restore seem failed. BUGS Report bugs to &dhemail; or . You can get support at http://partclone.org SEE ALSO partclone 8 , partclone.chkimg 8 , partclone.restore 8 , partclone.dd 8 , partclone.info 8
partclone-0.2.86/docs/partclone.exfat.8000066400000000000000000000000251262102574200177120ustar00rootroot00000000000000.so man8/partclone.8 partclone-0.2.86/docs/partclone.ext2.8000066400000000000000000000000251262102574200174650ustar00rootroot00000000000000.so man8/partclone.8 partclone-0.2.86/docs/partclone.ext3.8000066400000000000000000000000251262102574200174660ustar00rootroot00000000000000.so man8/partclone.8 partclone-0.2.86/docs/partclone.ext4.8000066400000000000000000000000251262102574200174670ustar00rootroot00000000000000.so man8/partclone.8 partclone-0.2.86/docs/partclone.ext4dev.8000066400000000000000000000000251262102574200201660ustar00rootroot00000000000000.so man8/partclone.8 partclone-0.2.86/docs/partclone.extfs.8000066400000000000000000000000251262102574200177340ustar00rootroot00000000000000.so man8/partclone.8 partclone-0.2.86/docs/partclone.f2fs.8000066400000000000000000000000251262102574200174430ustar00rootroot00000000000000.so man8/partclone.8 partclone-0.2.86/docs/partclone.fat.8000066400000000000000000000000251262102574200173550ustar00rootroot00000000000000.so man8/partclone.8 partclone-0.2.86/docs/partclone.fat12.8000066400000000000000000000000251262102574200175200ustar00rootroot00000000000000.so man8/partclone.8 partclone-0.2.86/docs/partclone.fat16.8000066400000000000000000000000251262102574200175240ustar00rootroot00000000000000.so man8/partclone.8 partclone-0.2.86/docs/partclone.fat32.8000066400000000000000000000000251262102574200175220ustar00rootroot00000000000000.so man8/partclone.8 partclone-0.2.86/docs/partclone.fstype.8000066400000000000000000000072131262102574200201230ustar00rootroot00000000000000'\" t .\" Title: PARTCLONE.FSTYPE .\" Author: Yu-Chin Tsai .\" Generator: DocBook XSL Stylesheets v1.78.1 .\" Date: 10/08/2015 .\" Manual: Partclone User Manual .\" Source: partclone.fstype .\" Language: English .\" .TH "PARTCLONE\&.FSTYPE" "8" "10/08/2015" "partclone.fstype" "Partclone User Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" partclone.fstype \- The utility to show vmfs type .SH "SYNOPSIS" .HP \w'\fBpartclone\&.fstype\fR\ 'u \fBpartclone\&.fstype\fR {\fIFILE\fR} .SH "DESCRIPTION" .PP \fBpartclone\&.fstype\fR is a part of \fBPartclone\fR project to retrive partition head information from image file\&. Partclone provide utilities to backup used blocks and design for higher compatibility of the file system by using existing library, e\&.g\&. e2fslibs is used to read the used block of ext2 partition\&. .PP \fBPartclone\fR supported file system include btrfs, ext2, ext3, ext4, reiserfs, reiser4, xfs and jfs for LINUX\&. Also support some non\-linux operation system, ex: NTFS, FAT, EXFAT(for Windows), HFS plus(APPLE MAC OS), UFS2(FreeBSD), VMFS(VMWare Vsphere)\&. All partclone utils could be run like partclone\&.xxx is very smiliar fsck or mkfs\&. For example, for backup/restore hfsplus, just run partclone\&.hfsp\&. .SH "OPTIONS" .PP The program follows the usual GNU command line syntax, with long options starting with two dashes (`\-\*(Aq)\&. A summary of options is included below\&. .PP \fB\fIDEVICE\fR\fR .RS 4 device of vmfs file system\&. .RE .SH "DIAGNOSTICS" .PP The following diagnostics may be issued on stderr: .PP \fBpartclone\&.fstype\fR provides some return codes, that can be used in scripts: .\" line length increase to cope w/ tbl weirdness .ll +(\n(LLu * 62u / 100u) .TS ll. \fICode\fR \fIDiagnostic\fR T{ \fB0\fR T} T{ Program exited successfully\&. T} T{ \fB1\fR T} T{ Clone or Restore seem failed\&. T} .TE .\" line length decrease back to previous value .ll -(\n(LLu * 62u / 100u) .sp .SH "BUGS" .PP Report bugs to thomas@nchc\&.org\&.tw or \m[blue]\fB\%http://partclone.org\fR\m[]\&. .PP You can get support at http://partclone\&.org .SH "SEE ALSO" .PP \fBpartclone\fR(8), \fBpartclone.chkimg\fR(8), \fBpartclone.restore\fR(8), \fBpartclone.dd\fR(8), \fBpartclone.info\fR(8) .SH "AUTHOR" .PP \fBYu\-Chin Tsai\fR <\&thomas@nchc\&.org\&.tw\&> .RS 4 .RE .SH "COPYRIGHT" .br Copyright \(co 2007 Yu-Chin Tsai .br .PP This manual page was written for the Debian system (and may be used by others)\&. .PP Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 2 or (at your option) any later version published by the Free Software Foundation\&. .PP On Debian systems, the complete text of the GNU General Public License can be found in /usr/share/common\-licenses/GPL\&. .sp partclone-0.2.86/docs/partclone.fstype.xml000066400000000000000000000162661262102574200205640ustar00rootroot00000000000000 .
will be generated. You may view the manual page with: nroff -man .
| less'. A typical entry in a Makefile or Makefile.am is: DB2MAN = /usr/share/sgml/docbookstylesheet/xsl/docbook-xsl/manpages/docbook.xsl XP = xsltproc -''-nonet -''-param man.charmap.use.subset "0" manpage.1: manpage.xml $(XP) $(DB2MAN) $< The xsltproc binary is found in the xsltproc package. The XSL files are in docbook-xsl. A description of the parameters you can use can be found in the docbook-xsl-doc-* packages. Please remember that if you create the nroff version in one of the debian/rules file targets (such as build), you will need to include xsltproc and docbook-xsl in your Build-Depends control field. Alternatively use the xmlto command/package. That will also automatically pull in xsltproc and docbook-xsl. Notes for using docbook2x: docbook2x-man does not automatically create the AUTHOR(S) and COPYRIGHT sections. In this case, please add them manually as ... . To disable the automatic creation of the AUTHOR(S) and COPYRIGHT sections read /usr/share/doc/docbook-xsl/doc/manpages/authors.html. This file can be found in the docbook-xsl-doc-html package. Validation can be done using: `xmllint -''-noout -''-valid manpage.xml` General documentation about man-pages and man-page-formatting: man(1), man(7), http://www.tldp.org/HOWTO/Man-Page/ --> ]> &dhtitle; &dhpackage; &dhfirstname; &dhsurname;
&dhemail;
2007 &dhusername; This manual page was written for the Debian system (and may be used by others). Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 2 or (at your option) any later version published by the Free Software Foundation. On Debian systems, the complete text of the GNU General Public License can be found in /usr/share/common-licenses/GPL.
&dhucpackage; &dhsection; &dhpackage; The utility to show vmfs type &dhpackage; FILE DESCRIPTION &dhpackage; is a part of Partclone project to retrive partition head information from image file. Partclone provide utilities to backup used blocks and design for higher compatibility of the file system by using existing library, e.g. e2fslibs is used to read the used block of ext2 partition. Partclone supported file system include btrfs, ext2, ext3, ext4, reiserfs, reiser4, xfs and jfs for LINUX. Also support some non-linux operation system, ex: NTFS, FAT, EXFAT(for Windows), HFS plus(APPLE MAC OS), UFS2(FreeBSD), VMFS(VMWare Vsphere). All partclone utils could be run like partclone.xxx is very smiliar fsck or mkfs. For example, for backup/restore hfsplus, just run partclone.hfsp. OPTIONS The program follows the usual GNU command line syntax, with long options starting with two dashes (`-'). A summary of options is included below. device of vmfs file system. DIAGNOSTICS The following diagnostics may be issued on stderr: &dhpackage; provides some return codes, that can be used in scripts: Code Diagnostic 0 Program exited successfully. 1 Clone or Restore seem failed. BUGS Report bugs to &dhemail; or . You can get support at http://partclone.org SEE ALSO partclone 8 , partclone.chkimg 8 , partclone.restore 8 , partclone.dd 8 , partclone.info 8
partclone-0.2.86/docs/partclone.hfs+.8000066400000000000000000000000251262102574200174360ustar00rootroot00000000000000.so man8/partclone.8 partclone-0.2.86/docs/partclone.hfsp.8000066400000000000000000000000251262102574200175430ustar00rootroot00000000000000.so man8/partclone.8 partclone-0.2.86/docs/partclone.hfsplus.8000066400000000000000000000000251262102574200202670ustar00rootroot00000000000000.so man8/partclone.8 partclone-0.2.86/docs/partclone.imager.8000066400000000000000000000163001262102574200200520ustar00rootroot00000000000000'\" t .\" Title: PARTCLONE.IMAGER .\" Author: Yu-Chin Tsai .\" Generator: DocBook XSL Stylesheets v1.78.1 .\" Date: 09/19/2015 .\" Manual: Partclone User Manual .\" Source: partclone.imager .\" Language: English .\" .TH "PARTCLONE\&.IMAGER" "8" "09/19/2015" "partclone.imager" "Partclone User Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" partclone.imager \- unsupported file system backup utility\&.(like `dd` ) .SH "SYNOPSIS" .HP \w'\fBpartclone\&.imager\fR\ 'u \fBpartclone\&.imager\fR {[\fB\-c\fR\ |\ \fB\-\-clone\fR]\ [\fB\-r\fR\ |\ \fB\-\-restore\fR]\ [\fB\-b\fR\ |\ \fB\-\-dev\-to\-dev\fR]} {[\fB\-s\fR\ |\ \fB\-\-source\fR]\ \fIsource\fR} {[[\fB\-o\fR\ |\ \fB\-\-output\fR]\ [\fB\-O\fR\ |\ \fB\-\-overwrite\fR]]\ \fItarget\fR} [[\fB\-dX\fR\ |\ \fB\-\-debug=X\fR]\ [\fB\-\-restore_raw_file\fR]\ [\fB\-z\fR\ |\ \fB\-\-buffer_size\fR]\ [\fB\-N\fR\ |\ \fB\-\-ncurses\fR]\ [\fB\-q\fR\ |\ \fB\-\-quiet\fR]\ [\fB\-f\fR\ |\ \fB\-\-UI\-fresh\fR]\ [\fB\-F\fR\ |\ \fB\-\-force\fR]\ [\fB\-I\fR\ |\ \fB\-\-ignore_fschk\fR]\ [\fB\-\-ignore_crc\fR]\ [\fB\-X\fR\ |\ \fB\-\-dialog\fR]\ [\fB\-C\fR\ |\ \fB\-\-nocheck\fR]\ [\fB\-R\fR\ |\ \fB\-\-rescue\fR]\ [\fB\-L\fR\ |\ \fB\-\-logfile\fR]\ \fIlogfile\fR] .SH "DESCRIPTION" .PP \fBpartclone\&.imager\fR is a part of \fBPartclone\fR project to clone unsupported file system with dd method\&. It will backup all block from partition\&. Partclone provide utilities to backup used blocks and design for higher compatibility of the file system by using existing library, e\&.g\&. e2fslibs is used to read the used block of ext2 partition\&. .PP \fBPartclone\fR supported file system include btrfs, ext2, ext3, ext4, reiserfs, reiser4, xfs and jfs for LINUX\&. Also support some non\-linux operation system, ex: NTFS and FAT (for Windows), HFS plus(APPLE MAC OS), UFS2(FreeBSD), VMFS(VMWare Vsphere)\&. All partclone utils could be run like partclone\&.xxx is very smiliar fsck or mkfs\&. For example, for backup/restore hfsplus, just run partclone\&.hfsp\&. .SH "OPTIONS" .PP The program follows the usual GNU command line syntax, with long options starting with two dashes (`\-\*(Aq)\&. A summary of options is included below\&. .PP \fB\-s \fR\fB\fIFILE\fR\fR, \fB\-\-source \fR\fB\fIFILE\fR\fR .RS 4 Source FILE\&. The FILE could be a image file(made by partclone) or device depend on your action\&. Normanly, backup source is device, restore source is image file\&. .sp Receving data from pipe line is supported ONLY for restoring, just ignore \-s option or use \*(Aq\-\*(Aq means receive data from stdin\&. .RE .PP \fB\-o \fR\fB\fIFILE\fR\fR, \fB\-\-output \fR\fB\fIFILE\fR\fR .RS 4 Output FILE\&. The FILE could be a image file(partclone will generate) or device depend on your action\&. Normanly, backup output to image file and restore output to device\&. .sp Sending data to pipe line is also supported ONLY for back\-up, just ignore \-o option or use \*(Aq\-\*(Aq means send data to stdout\&. .RE .PP \fB\-O \fR\fB\fIFILE\fR\fR, \fB\-\-overwrite \fR\fB\fIFILE\fR\fR .RS 4 Overwrite FILE, overwriting if exists\&. .RE .PP \fB\-c\fR, \fB\-\-clone\fR .RS 4 Save partition to the special image format\&. .RE .PP \fB\-r\fR, \fB\-\-restore\fR .RS 4 Restore partition from the special image format\&. .RE .PP \fB\-b\fR, \fB\-\-dev\-to\-dev\fR .RS 4 Local device to device copy on\-the\-fly, source and output both are device\&. .RE .PP \fB\-\-restore_raw_file\fR .RS 4 Creating special raw file for loop device\&. .RE .PP \fB\-l \fR\fB\fIFILE\fR\fR, \fB\-\-logfile \fR\fB\fIFILE\fR\fR .RS 4 put special path to record partclone log information\&.(default /var/log/partclone\&.log) .RE .PP \fB\-R\fR, \fB\-\-rescue\fR .RS 4 Continue after disk read errors\&. .RE .PP \fB\-C\fR, \fB\-\-no_check\fR .RS 4 Don\*(Aqt check device size and free space\&. .RE .PP \fB\-N\fR, \fB\-\-ncurse\fR .RS 4 Using Ncurses Text User Interface\&. .RE .PP \fB\-X\fR, \fB\-\-dialog\fR .RS 4 Output message as Dialog Format\&. .RE .PP \fB\-I\fR, \fB\-\-ignore_fschk\fR .RS 4 Ignore filesystem check\&. .RE .PP \fB\-\-ignore_crc\fR .RS 4 Ignore crc check error\&. .RE .PP \fB\-F\fR, \fB\-\-force\fR .RS 4 Force progress\&. .RE .PP \fB\-f \fR\fB\fIsec\fR\fR, \fB\-\-UI\-fresh \fR\fB\fIsec\fR\fR .RS 4 put special second to different interval\&. .RE .PP \fB\-z \fR\fB\fIsize\fR\fR, \fB\-\-buffer_size \fR\fB\fIsize\fR\fR .RS 4 Read/write buffer size (default: 1048576) .RE .PP \fB\-q\fR, \fB\-\-quiet\fR .RS 4 Disable progress message\&. .RE .PP \fB\-d\fR\fB\fIlevel\fR\fR, \fB\-\-debug \fR\fB\fIlevel\fR\fR .RS 4 Set the debug level [1|2|3] .RE .PP \fB\-h\fR, \fB\-\-help\fR .RS 4 Show summary of options\&. .RE .PP \fB\-v\fR, \fB\-\-version\fR .RS 4 Show version of program\&. .RE .SH "FILES" .PP /var/log/partclone\&.log .RS 4 The log file of partclone\&.imager .RE .SH "EXAMPLES" .sp .if n \{\ .RS 4 .\} .nf clone /dev/hda1 to hda1\&.dd\&.img and display debug information\&. partclone\&.dd \-c \-d \-s /dev/hda1 \-o hda1\&.dd\&.img restore /dev/hda1 from hda1\&.dd\&.img and display debug information\&. partclone\&.dd \-r \-d \-s hda1\&.dd\&.img \-o /dev/hda1 .fi .if n \{\ .RE .\} .SH "DIAGNOSTICS" .PP The following diagnostics may be issued on stderr: .PP \fBpartclone\&.imager\fR provides some return codes, that can be used in scripts: .\" line length increase to cope w/ tbl weirdness .ll +(\n(LLu * 62u / 100u) .TS ll. \fICode\fR \fIDiagnostic\fR T{ \fB0\fR T} T{ Program exited successfully\&. T} T{ \fB1\fR T} T{ Clone or Restore seem failed\&. T} .TE .\" line length decrease back to previous value .ll -(\n(LLu * 62u / 100u) .sp .SH "BUGS" .PP Report bugs to thomas@nchc\&.org\&.tw or \m[blue]\fB\%http://partclone.org\fR\m[]\&. .PP You can get support at http://partclone\&.org .SH "SEE ALSO" .PP \fBpartclone\fR(8), \fBpartclone.chkimg\fR(8), \fBpartclone.restore\fR(8), \fBpartclone.dd\fR(8), \fBpartclone.info\fR(8) .SH "AUTHOR" .PP \fBYu\-Chin Tsai\fR <\&thomas@nchc\&.org\&.tw\&> .RS 4 .RE .SH "COPYRIGHT" .br Copyright \(co 2007 Yu-Chin Tsai .br .PP This manual page was written for the Debian system (and may be used by others)\&. .PP Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 2 or (at your option) any later version published by the Free Software Foundation\&. .PP On Debian systems, the complete text of the GNU General Public License can be found in /usr/share/common\-licenses/GPL\&. .sp partclone-0.2.86/docs/partclone.imager.xml000066400000000000000000000402261262102574200205070ustar00rootroot00000000000000 .
will be generated. You may view the manual page with: nroff -man .
| less'. A typical entry in a Makefile or Makefile.am is: DB2MAN = /usr/share/sgml/docbookstylesheet/xsl/docbook-xsl/manpages/docbook.xsl XP = xsltproc -''-nonet -''-param man.charmap.use.subset "0" manpage.1: manpage.xml $(XP) $(DB2MAN) $< The xsltproc binary is found in the xsltproc package. The XSL files are in docbook-xsl. A description of the parameters you can use can be found in the docbook-xsl-doc-* packages. Please remember that if you create the nroff version in one of the debian/rules file targets (such as build), you will need to include xsltproc and docbook-xsl in your Build-Depends control field. Alternatively use the xmlto command/package. That will also automatically pull in xsltproc and docbook-xsl. Notes for using docbook2x: docbook2x-man does not automatically create the AUTHOR(S) and COPYRIGHT sections. In this case, please add them manually as ... . To disable the automatic creation of the AUTHOR(S) and COPYRIGHT sections read /usr/share/doc/docbook-xsl/doc/manpages/authors.html. This file can be found in the docbook-xsl-doc-html package. Validation can be done using: `xmllint -''-noout -''-valid manpage.xml` General documentation about man-pages and man-page-formatting: man(1), man(7), http://www.tldp.org/HOWTO/Man-Page/ --> ]> &dhtitle; &dhpackage; &dhfirstname; &dhsurname;
&dhemail;
2007 &dhusername; This manual page was written for the Debian system (and may be used by others). Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 2 or (at your option) any later version published by the Free Software Foundation. On Debian systems, the complete text of the GNU General Public License can be found in /usr/share/common-licenses/GPL.
&dhucpackage; &dhsection; &dhpackage; unsupported file system backup utility.(like `dd` ) &dhpackage; source target logfile DESCRIPTION &dhpackage; is a part of Partclone project to clone unsupported file system with dd method. It will backup all block from partition. Partclone provide utilities to backup used blocks and design for higher compatibility of the file system by using existing library, e.g. e2fslibs is used to read the used block of ext2 partition. Partclone supported file system include btrfs, ext2, ext3, ext4, reiserfs, reiser4, xfs and jfs for LINUX. Also support some non-linux operation system, ex: NTFS and FAT (for Windows), HFS plus(APPLE MAC OS), UFS2(FreeBSD), VMFS(VMWare Vsphere). All partclone utils could be run like partclone.xxx is very smiliar fsck or mkfs. For example, for backup/restore hfsplus, just run partclone.hfsp. OPTIONS The program follows the usual GNU command line syntax, with long options starting with two dashes (`-'). A summary of options is included below. Source FILE. The FILE could be a image file(made by partclone) or device depend on your action. Normanly, backup source is device, restore source is image file. Receving data from pipe line is supported ONLY for restoring, just ignore -s option or use '-' means receive data from stdin. Output FILE. The FILE could be a image file(partclone will generate) or device depend on your action. Normanly, backup output to image file and restore output to device. Sending data to pipe line is also supported ONLY for back-up, just ignore -o option or use '-' means send data to stdout. Overwrite FILE, overwriting if exists. Save partition to the special image format. Restore partition from the special image format. Local device to device copy on-the-fly, source and output both are device. Creating special raw file for loop device. put special path to record partclone log information.(default /var/log/partclone.log) Continue after disk read errors. Don't check device size and free space. Using Ncurses Text User Interface. Output message as Dialog Format. Ignore filesystem check. Ignore crc check error. Force progress. put special second to different interval. Read/write buffer size (default: 1048576) Disable progress message. Set the debug level [1|2|3] Show summary of options. Show version of program. FILES /var/log/partclone.log The log file of &dhpackage; EXAMPLES clone /dev/hda1 to hda1.dd.img and display debug information. partclone.dd -c -d -s /dev/hda1 -o hda1.dd.img restore /dev/hda1 from hda1.dd.img and display debug information. partclone.dd -r -d -s hda1.dd.img -o /dev/hda1 DIAGNOSTICS The following diagnostics may be issued on stderr: &dhpackage; provides some return codes, that can be used in scripts: Code Diagnostic 0 Program exited successfully. 1 Clone or Restore seem failed. BUGS Report bugs to &dhemail; or . You can get support at http://partclone.org SEE ALSO partclone 8 , partclone.chkimg 8 , partclone.restore 8 , partclone.dd 8 , partclone.info 8
partclone-0.2.86/docs/partclone.info.8000066400000000000000000000100361262102574200175410ustar00rootroot00000000000000'\" t .\" Title: PARTCLONE.INFO .\" Author: Yu-Chin Tsai .\" Generator: DocBook XSL Stylesheets v1.78.1 .\" Date: 09/19/2015 .\" Manual: Partclone User Manual .\" Source: partclone.info .\" Language: English .\" .TH "PARTCLONE\&.INFO" "8" "09/19/2015" "partclone.info" "Partclone User Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" partclone.info \- The utility to show image head information\&. .SH "SYNOPSIS" .HP \w'\fBpartclone\&.info\fR\ 'u \fBpartclone\&.info\fR {\fIFILE\fR} .SH "DESCRIPTION" .PP \fBpartclone\&.info\fR is a part of \fBPartclone\fR project to retrive partition head information from image file\&. Partclone provide utilities to backup used blocks and design for higher compatibility of the file system by using existing library, e\&.g\&. e2fslibs is used to read the used block of ext2 partition\&. .PP \fBPartclone\fR supported file system include btrfs, ext2, ext3, ext4, reiserfs, reiser4, xfs and jfs for LINUX\&. Also support some non\-linux operation system, ex: NTFS, FAT, EXFAT(for Windows), HFS plus(APPLE MAC OS), UFS2(FreeBSD), VMFS(VMWare Vsphere)\&. All partclone utils could be run like partclone\&.xxx is very smiliar fsck or mkfs\&. For example, for backup/restore hfsplus, just run partclone\&.hfsp\&. .SH "OPTIONS" .PP The program follows the usual GNU command line syntax, with long options starting with two dashes (`\-\*(Aq)\&. A summary of options is included below\&. .PP \fB\fIFILE\fR\fR .RS 4 Image FILE\&. The FILE could be a image file(made by partclone)\&. .RE .SH "EXAMPLES" .sp .if n \{\ .RS 4 .\} .nf Retriving partition usage information partclone\&.info /home/partimag/sdb2\&.img Partclone v0\&.2\&.20 http://partclone\&.org File system: EXTFS Device size: 928\&.0 MB Space in use: 535\&.4 MB Free Space: 392\&.6 MB Block size: 4096 Byte Used block : 130708 .fi .if n \{\ .RE .\} .SH "DIAGNOSTICS" .PP The following diagnostics may be issued on stderr: .PP \fBpartclone\&.info\fR provides some return codes, that can be used in scripts: .\" line length increase to cope w/ tbl weirdness .ll +(\n(LLu * 62u / 100u) .TS ll. \fICode\fR \fIDiagnostic\fR T{ \fB0\fR T} T{ Program exited successfully\&. T} T{ \fB1\fR T} T{ Clone or Restore seem failed\&. T} .TE .\" line length decrease back to previous value .ll -(\n(LLu * 62u / 100u) .sp .SH "BUGS" .PP Report bugs to thomas@nchc\&.org\&.tw or \m[blue]\fB\%http://partclone.org\fR\m[]\&. .PP You can get support at http://partclone\&.org .SH "SEE ALSO" .PP \fBpartclone\fR(8), \fBpartclone.chkimg\fR(8), \fBpartclone.restore\fR(8), \fBpartclone.dd\fR(8), \fBpartclone.info\fR(8) .SH "AUTHOR" .PP \fBYu\-Chin Tsai\fR <\&thomas@nchc\&.org\&.tw\&> .RS 4 .RE .SH "COPYRIGHT" .br Copyright \(co 2007 Yu-Chin Tsai .br .PP This manual page was written for the Debian system (and may be used by others)\&. .PP Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 2 or (at your option) any later version published by the Free Software Foundation\&. .PP On Debian systems, the complete text of the GNU General Public License can be found in /usr/share/common\-licenses/GPL\&. .sp partclone-0.2.86/docs/partclone.info.xml000066400000000000000000000171371262102574200202030ustar00rootroot00000000000000 .
will be generated. You may view the manual page with: nroff -man .
| less'. A typical entry in a Makefile or Makefile.am is: DB2MAN = /usr/share/sgml/docbookstylesheet/xsl/docbook-xsl/manpages/docbook.xsl XP = xsltproc -''-nonet -''-param man.charmap.use.subset "0" manpage.1: manpage.xml $(XP) $(DB2MAN) $< The xsltproc binary is found in the xsltproc package. The XSL files are in docbook-xsl. A description of the parameters you can use can be found in the docbook-xsl-doc-* packages. Please remember that if you create the nroff version in one of the debian/rules file targets (such as build), you will need to include xsltproc and docbook-xsl in your Build-Depends control field. Alternatively use the xmlto command/package. That will also automatically pull in xsltproc and docbook-xsl. Notes for using docbook2x: docbook2x-man does not automatically create the AUTHOR(S) and COPYRIGHT sections. In this case, please add them manually as ... . To disable the automatic creation of the AUTHOR(S) and COPYRIGHT sections read /usr/share/doc/docbook-xsl/doc/manpages/authors.html. This file can be found in the docbook-xsl-doc-html package. Validation can be done using: `xmllint -''-noout -''-valid manpage.xml` General documentation about man-pages and man-page-formatting: man(1), man(7), http://www.tldp.org/HOWTO/Man-Page/ --> ]> &dhtitle; &dhpackage; &dhfirstname; &dhsurname;
&dhemail;
2007 &dhusername; This manual page was written for the Debian system (and may be used by others). Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 2 or (at your option) any later version published by the Free Software Foundation. On Debian systems, the complete text of the GNU General Public License can be found in /usr/share/common-licenses/GPL.
&dhucpackage; &dhsection; &dhpackage; The utility to show image head information. &dhpackage; FILE DESCRIPTION &dhpackage; is a part of Partclone project to retrive partition head information from image file. Partclone provide utilities to backup used blocks and design for higher compatibility of the file system by using existing library, e.g. e2fslibs is used to read the used block of ext2 partition. Partclone supported file system include btrfs, ext2, ext3, ext4, reiserfs, reiser4, xfs and jfs for LINUX. Also support some non-linux operation system, ex: NTFS, FAT, EXFAT(for Windows), HFS plus(APPLE MAC OS), UFS2(FreeBSD), VMFS(VMWare Vsphere). All partclone utils could be run like partclone.xxx is very smiliar fsck or mkfs. For example, for backup/restore hfsplus, just run partclone.hfsp. OPTIONS The program follows the usual GNU command line syntax, with long options starting with two dashes (`-'). A summary of options is included below. Image FILE. The FILE could be a image file(made by partclone). EXAMPLES Retriving partition usage information partclone.info /home/partimag/sdb2.img Partclone v0.2.20 http://partclone.org File system: EXTFS Device size: 928.0 MB Space in use: 535.4 MB Free Space: 392.6 MB Block size: 4096 Byte Used block : 130708 DIAGNOSTICS The following diagnostics may be issued on stderr: &dhpackage; provides some return codes, that can be used in scripts: Code Diagnostic 0 Program exited successfully. 1 Clone or Restore seem failed. BUGS Report bugs to &dhemail; or . You can get support at http://partclone.org SEE ALSO partclone 8 , partclone.chkimg 8 , partclone.restore 8 , partclone.dd 8 , partclone.info 8
partclone-0.2.86/docs/partclone.jfs.8000066400000000000000000000000251262102574200173650ustar00rootroot00000000000000.so man8/partclone.8 partclone-0.2.86/docs/partclone.minix.8000066400000000000000000000000251262102574200177270ustar00rootroot00000000000000.so man8/partclone.8 partclone-0.2.86/docs/partclone.nilfs2.8000066400000000000000000000000251262102574200200000ustar00rootroot00000000000000.so man8/partclone.8 partclone-0.2.86/docs/partclone.ntfs.8000066400000000000000000000000251262102574200175550ustar00rootroot00000000000000.so man8/partclone.8 partclone-0.2.86/docs/partclone.ntfsfixboot.8000066400000000000000000000104501262102574200211530ustar00rootroot00000000000000'\" t .\" Title: PARTCLONE.NTFSFIXBOOT .\" Author: Yu-Chin Tsai .\" Generator: DocBook XSL Stylesheets v1.78.1 .\" Date: 10/08/2015 .\" Manual: Partclone User Manual .\" Source: partclone.ntfsfixboot .\" Language: English .\" .TH "PARTCLONE\&.NTFSFIXB" "8" "10/08/2015" "partclone.ntfsfixboot" "Partclone User Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" partclone.ntfsfixboot \- deals with braindeadness with moving NTFS filesystems\&. .SH "SYNOPSIS" .HP \w'\fBpartclone\&.ntfsfixboot\fR\ 'u \fBpartclone\&.ntfsfixboot\fR [\fB\-w\fR] [\fB\-h\fR\ \fIn\fR] [\fB\-t\fR\ \fIn\fR] [\fB\-s\fR\ \fIn\fR] [\fB\-b\fR] [\fB\-f\fR] [\fB\-p\fR] {\fIDEVICE\fR} .SH "DESCRIPTION" .PP \fBpartclone\&.ntfsfixboot\fR is NOT a part of \fBPartclone\fR project but included to fix ntfs boot issue\&. Partclone provide utilities to backup used blocks and design for higher compatibility of the file system by using existing library, e\&.g\&. e2fslibs is used to read the used block of ext2 partition\&. .PP \fBPartclone\&.ntfsfixboot\fR deals with braindeadness with moving NTFS filesystems\&. writted by Orgad Shaneh (2009) and Daniel J\&. Grace (2006)\&. .SH "OPTIONS" .PP The program follows the usual GNU command line syntax,a summary of options is included below\&. .PP \fB \-w \fR .RS 4 Write new start sector to the partition\&. .RE .PP \fB \-h \fR\fInum\fR .RS 4 Specify number of heads per track\&. If omitted, determined via ioctl\&. .RE .PP \fB \-t \fR\fInum\fR .RS 4 Specify number of sectors per track\&. If omitted, determined via ioctl\&. .RE .PP \fB \-s \fR\fInum\fR .RS 4 New start sector to write\&. If omitted, determined via ioctl\&. .RE .PP \fB \-b \fR .RS 4 Proceed even if the specified device is not a partition\&. .RE .PP \fB \-f \fR .RS 4 Force the operation to occur even if device does not look like a valid NTFS partition or values are equal\&. .RE .PP \fB \-p \fR .RS 4 Print debug information (values read, values requested etc\&. .RE .PP \fB\fIdevice\fR\fR .RS 4 where device points to an NTFS partition .RE .SH "DIAGNOSTICS" .PP The following diagnostics may be issued on stderr: .PP \fBpartclone\&.ntfsfixboot\fR provides some return codes, that can be used in scripts: .\" line length increase to cope w/ tbl weirdness .ll +(\n(LLu * 62u / 100u) .TS ll. \fICode\fR \fIDiagnostic\fR T{ \fB0\fR T} T{ success (values are correct, or changed successfully) T} T{ \fB1\fR T} T{ a change is needed, but \-w was not specified T} T{ \fB2\fR T} T{ an error occured T} .TE .\" line length decrease back to previous value .ll -(\n(LLu * 62u / 100u) .sp .SH "BUGS" .PP Report bugs to thomas@nchc\&.org\&.tw or \m[blue]\fB\%http://partclone.org\fR\m[]\&. .PP Report bugs to upstrem \m[blue]\fB\%http://sourceforge.net/projects/ntfsfixboot/\fR\m[]\&. .SH "SEE ALSO" .PP \fBpartclone\fR(8), \fBpartclone.chkimg\fR(8), \fBpartclone.restore\fR(8), \fBpartclone.dd\fR(8), \fBpartclone.info\fR(8) .SH "AUTHOR" .PP \fBYu\-Chin Tsai\fR <\&thomas@nchc\&.org\&.tw\&> .RS 4 .RE .SH "COPYRIGHT" .br Copyright \(co 2007 Yu-Chin Tsai .br .PP This manual page was written for the Debian system (and may be used by others)\&. .PP Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 2 or (at your option) any later version published by the Free Software Foundation\&. .PP On Debian systems, the complete text of the GNU General Public License can be found in /usr/share/common\-licenses/GPL\&. .sp partclone-0.2.86/docs/partclone.ntfsfixboot.xml000066400000000000000000000221611262102574200216060ustar00rootroot00000000000000 .
will be generated. You may view the manual page with: nroff -man .
| less'. A typical entry in a Makefile or Makefile.am is: DB2MAN = /usr/share/sgml/docbookstylesheet/xsl/docbook-xsl/manpages/docbook.xsl XP = xsltproc -''-nonet -''-param man.charmap.use.subset "0" manpage.1: manpage.xml $(XP) $(DB2MAN) $< The xsltproc binary is found in the xsltproc package. The XSL files are in docbook-xsl. A description of the parameters you can use can be found in the docbook-xsl-doc-* packages. Please remember that if you create the nroff version in one of the debian/rules file targets (such as build), you will need to include xsltproc and docbook-xsl in your Build-Depends control field. Alternatively use the xmlto command/package. That will also automatically pull in xsltproc and docbook-xsl. Notes for using docbook2x: docbook2x-man does not automatically create the AUTHOR(S) and COPYRIGHT sections. In this case, please add them manually as ... . To disable the automatic creation of the AUTHOR(S) and COPYRIGHT sections read /usr/share/doc/docbook-xsl/doc/manpages/authors.html. This file can be found in the docbook-xsl-doc-html package. Validation can be done using: `xmllint -''-noout -''-valid manpage.xml` General documentation about man-pages and man-page-formatting: man(1), man(7), http://www.tldp.org/HOWTO/Man-Page/ --> ]> &dhtitle; &dhpackage; &dhfirstname; &dhsurname;
&dhemail;
2007 &dhusername; This manual page was written for the Debian system (and may be used by others). Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 2 or (at your option) any later version published by the Free Software Foundation. On Debian systems, the complete text of the GNU General Public License can be found in /usr/share/common-licenses/GPL.
&dhucpackage; &dhsection; &dhpackage; deals with braindeadness with moving NTFS filesystems. &dhpackage; n n n DEVICE DESCRIPTION &dhpackage; is NOT a part of Partclone project but included to fix ntfs boot issue. Partclone provide utilities to backup used blocks and design for higher compatibility of the file system by using existing library, e.g. e2fslibs is used to read the used block of ext2 partition. Partclone.ntfsfixboot deals with braindeadness with moving NTFS filesystems. writted by Orgad Shaneh (2009) and Daniel J. Grace (2006). OPTIONS The program follows the usual GNU command line syntax,a summary of options is included below. Write new start sector to the partition. num Specify number of heads per track. If omitted, determined via ioctl. num Specify number of sectors per track. If omitted, determined via ioctl. num New start sector to write. If omitted, determined via ioctl. Proceed even if the specified device is not a partition. Force the operation to occur even if device does not look like a valid NTFS partition or values are equal. Print debug information (values read, values requested etc. where device points to an NTFS partition DIAGNOSTICS The following diagnostics may be issued on stderr: &dhpackage; provides some return codes, that can be used in scripts: Code Diagnostic 0 success (values are correct, or changed successfully) 1 a change is needed, but -w was not specified 2 an error occured BUGS Report bugs to &dhemail; or . Report bugs to upstrem . SEE ALSO partclone 8 , partclone.chkimg 8 , partclone.restore 8 , partclone.dd 8 , partclone.info 8
partclone-0.2.86/docs/partclone.ntfsreloc.8000066400000000000000000000000411262102574200206000ustar00rootroot00000000000000.so man8/partclone.ntfsfixboot.8 partclone-0.2.86/docs/partclone.reiser4.8000066400000000000000000000000251262102574200201600ustar00rootroot00000000000000.so man8/partclone.8 partclone-0.2.86/docs/partclone.reiserfs.8000066400000000000000000000000251262102574200204250ustar00rootroot00000000000000.so man8/partclone.8 partclone-0.2.86/docs/partclone.restore.8000066400000000000000000000156611262102574200203020ustar00rootroot00000000000000'\" t .\" Title: PARTCLONE.RESTORE .\" Author: Yu-Chin Tsai .\" Generator: DocBook XSL Stylesheets v1.78.1 .\" Date: 09/19/2015 .\" Manual: Partclone User Manual .\" Source: partclone.restore .\" Language: English .\" .TH "PARTCLONE\&.RESTORE" "8" "09/19/2015" "partclone.restore" "Partclone User Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" partclone.restore \- restore partclone image to device\&. .SH "SYNOPSIS" .HP \w'\fBpartclone\&.restore\fR\ 'u \fBpartclone\&.restore\fR {[\fB\-s\fR\ |\ \fB\-\-source\fR]\ \fIsource\fR} {[[\fB\-o\fR\ |\ \fB\-\-output\fR]\ [\fB\-O\fR\ |\ \fB\-\-overwrite\fR]]\ \fItarget\fR} [[\fB\-dX\fR\ |\ \fB\-\-debug=X\fR]\ [\fB\-\-restore_raw_file\fR]\ [\fB\-z\fR\ |\ \fB\-\-buffer_size\fR]\ [\fB\-N\fR\ |\ \fB\-\-ncurses\fR]\ [\fB\-q\fR\ |\ \fB\-\-quiet\fR]\ [\fB\-f\fR\ |\ \fB\-\-UI\-fresh\fR]\ [\fB\-F\fR\ |\ \fB\-\-force\fR]\ [\fB\-I\fR\ |\ \fB\-\-ignore_fschk\fR]\ [\fB\-\-ignore_crc\fR]\ [\fB\-X\fR\ |\ \fB\-\-dialog\fR]\ [\fB\-C\fR\ |\ \fB\-\-nocheck\fR]\ [\fB\-R\fR\ |\ \fB\-\-rescue\fR]\ [\fB\-L\fR\ |\ \fB\-\-logfile\fR]\ \fIlogfile\fR] .SH "DESCRIPTION" .PP \fBpartclone\&.restore\fR is a part of \fBPartclone\fR project to restore all image made from partclone\&.[fstype] or partclone\&.dd\&. Partclone provide utilities to backup used blocks and design for higher compatibility of the file system by using existing library, e\&.g\&. e2fslibs is used to read the used block of ext2 partition\&. .PP \fBPartclone\fR supported file system include btrfs, ext2, ext3, ext4, reiserfs, reiser4, xfs and jfs for LINUX\&. Also support some non\-linux operation system, ex: NTFS, FAT, EXFAT(for Windows), HFS plus(APPLE MAC OS), UFS2(FreeBSD), VMFS(VMWare Vsphere)\&. All partclone utils could be run like partclone\&.xxx is very smiliar fsck or mkfs\&. For example, for backup/restore hfsplus, just run partclone\&.hfsp\&. .SH "OPTIONS" .PP The program follows the usual GNU command line syntax, with long options starting with two dashes (`\-\*(Aq)\&. A summary of options is included below\&. .PP \fB\-s \fR\fB\fIFILE\fR\fR, \fB\-\-source \fR\fB\fIFILE\fR\fR .RS 4 Source FILE\&. The FILE could be a image file(made by partclone) or device depend on your action\&. Normanly, backup source is device, restore source is image file\&. .sp Receving data from pipe line is supported ONLY for restoring, just ignore \-s option or use \*(Aq\-\*(Aq means receive data from stdin\&. .RE .PP \fB\-o \fR\fB\fIFILE\fR\fR, \fB\-\-output \fR\fB\fIFILE\fR\fR .RS 4 Output FILE\&. The FILE could be a image file(partclone will generate) or device depend on your action\&. Normanly, backup output to image file and restore output to device\&. .sp Sending data to pipe line is also supported ONLY for back\-up, just ignore \-o option or use \*(Aq\-\*(Aq means send data to stdout\&. .RE .PP \fB\-O \fR\fB\fIFILE\fR\fR, \fB\-\-overwrite \fR\fB\fIFILE\fR\fR .RS 4 Overwrite FILE, overwriting if exists\&. .RE .PP \fB\-\-restore_raw_file\fR .RS 4 Creating special raw file for loop device\&. .RE .PP \fB\-l \fR\fB\fIFILE\fR\fR, \fB\-\-logfile \fR\fB\fIFILE\fR\fR .RS 4 put special path to record partclone log information\&.(default /var/log/partclone\&.log) .RE .PP \fB\-R\fR, \fB\-\-rescue\fR .RS 4 Continue after disk read errors\&. .RE .PP \fB\-C\fR, \fB\-\-no_check\fR .RS 4 Don\*(Aqt check device size and free space\&. .RE .PP \fB\-N\fR, \fB\-\-ncurse\fR .RS 4 Using Ncurses Text User Interface\&. .RE .PP \fB\-X\fR, \fB\-\-dialog\fR .RS 4 Output message as Dialog Format\&. .RE .PP \fB\-I\fR, \fB\-\-ignore_fschk\fR .RS 4 Ignore filesystem check\&. .RE .PP \fB\-\-ignore_crc\fR .RS 4 Ignore crc check error\&. .RE .PP \fB\-F\fR, \fB\-\-force\fR .RS 4 Force progress\&. .RE .PP \fB\-f \fR\fB\fIsec\fR\fR, \fB\-\-UI\-fresh \fR\fB\fIsec\fR\fR .RS 4 put special second to different interval\&. .RE .PP \fB\-z \fR\fB\fIsize\fR\fR, \fB\-\-buffer_size \fR\fB\fIsize\fR\fR .RS 4 Read/write buffer size (default: 1048576) .RE .PP \fB\-q\fR, \fB\-\-quiet\fR .RS 4 Disable progress message\&. .RE .PP \fB\-d\fR\fB\fIlevel\fR\fR, \fB\-\-debug \fR\fB\fIlevel\fR\fR .RS 4 Set the debug level [1|2|3] .RE .PP \fB\-h\fR, \fB\-\-help\fR .RS 4 Show summary of options\&. .RE .PP \fB\-v\fR, \fB\-\-version\fR .RS 4 Show version of program\&. .RE .SH "FILES" .PP /var/log/partclone\&.log .RS 4 The log file of partclone\&.restore .RE .SH "EXAMPLES" .sp .if n \{\ .RS 4 .\} .nf restore /dev/hda1 from hda1\&.img and display debug information\&. partclone\&.restore \-d \-s hda1\&.img \-o /dev/hda1 restore image from clonezilla(split, gzip,) with stdin source cat sda1\&.ext3\-ptcl\-img\&.gz\&.a* | gunzip \-c | partclone\&.restore \-d \-s \- \-o /dev/sda1 restore raw image from partclone\&.dd partclone\&.dd \-d \-c \-s /dev/sda1 \-o \- | partclone\&.restore \-d \-s \- \-o /dev/sdb1 .fi .if n \{\ .RE .\} .SH "DIAGNOSTICS" .PP The following diagnostics may be issued on stderr: .PP \fBpartclone\&.restore\fR provides some return codes, that can be used in scripts: .\" line length increase to cope w/ tbl weirdness .ll +(\n(LLu * 62u / 100u) .TS ll. \fICode\fR \fIDiagnostic\fR T{ \fB0\fR T} T{ Program exited successfully\&. T} T{ \fB1\fR T} T{ Clone or Restore seem failed\&. T} .TE .\" line length decrease back to previous value .ll -(\n(LLu * 62u / 100u) .sp .SH "BUGS" .PP Report bugs to thomas@nchc\&.org\&.tw or \m[blue]\fB\%http://partclone.org\fR\m[]\&. .PP You can get support at http://partclone\&.org .SH "SEE ALSO" .PP \fBpartclone\fR(8), \fBpartclone.chkimg\fR(8), \fBpartclone.restore\fR(8), \fBpartclone.dd\fR(8), \fBpartclone.info\fR(8) .SH "AUTHOR" .PP \fBYu\-Chin Tsai\fR <\&thomas@nchc\&.org\&.tw\&> .RS 4 .RE .SH "COPYRIGHT" .br Copyright \(co 2007 Yu-Chin Tsai .br .PP This manual page was written for the Debian system (and may be used by others)\&. .PP Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 2 or (at your option) any later version published by the Free Software Foundation\&. .PP On Debian systems, the complete text of the GNU General Public License can be found in /usr/share/common\-licenses/GPL\&. .sp partclone-0.2.86/docs/partclone.restore.xml000066400000000000000000000361361262102574200207330ustar00rootroot00000000000000 .
will be generated. You may view the manual page with: nroff -man .
| less'. A typical entry in a Makefile or Makefile.am is: DB2MAN = /usr/share/sgml/docbookstylesheet/xsl/docbook-xsl/manpages/docbook.xsl XP = xsltproc -''-nonet -''-param man.charmap.use.subset "0" manpage.1: manpage.xml $(XP) $(DB2MAN) $< The xsltproc binary is found in the xsltproc package. The XSL files are in docbook-xsl. A description of the parameters you can use can be found in the docbook-xsl-doc-* packages. Please remember that if you create the nroff version in one of the debian/rules file targets (such as build), you will need to include xsltproc and docbook-xsl in your Build-Depends control field. Alternatively use the xmlto command/package. That will also automatically pull in xsltproc and docbook-xsl. Notes for using docbook2x: docbook2x-man does not automatically create the AUTHOR(S) and COPYRIGHT sections. In this case, please add them manually as ... . To disable the automatic creation of the AUTHOR(S) and COPYRIGHT sections read /usr/share/doc/docbook-xsl/doc/manpages/authors.html. This file can be found in the docbook-xsl-doc-html package. Validation can be done using: `xmllint -''-noout -''-valid manpage.xml` General documentation about man-pages and man-page-formatting: man(1), man(7), http://www.tldp.org/HOWTO/Man-Page/ --> ]> &dhtitle; &dhpackage; &dhfirstname; &dhsurname;
&dhemail;
2007 &dhusername; This manual page was written for the Debian system (and may be used by others). Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 2 or (at your option) any later version published by the Free Software Foundation. On Debian systems, the complete text of the GNU General Public License can be found in /usr/share/common-licenses/GPL.
&dhucpackage; &dhsection; &dhpackage; restore partclone image to device. &dhpackage; source target logfile DESCRIPTION &dhpackage; is a part of Partclone project to restore all image made from partclone.[fstype] or partclone.dd. Partclone provide utilities to backup used blocks and design for higher compatibility of the file system by using existing library, e.g. e2fslibs is used to read the used block of ext2 partition. Partclone supported file system include btrfs, ext2, ext3, ext4, reiserfs, reiser4, xfs and jfs for LINUX. Also support some non-linux operation system, ex: NTFS, FAT, EXFAT(for Windows), HFS plus(APPLE MAC OS), UFS2(FreeBSD), VMFS(VMWare Vsphere). All partclone utils could be run like partclone.xxx is very smiliar fsck or mkfs. For example, for backup/restore hfsplus, just run partclone.hfsp. OPTIONS The program follows the usual GNU command line syntax, with long options starting with two dashes (`-'). A summary of options is included below. Source FILE. The FILE could be a image file(made by partclone) or device depend on your action. Normanly, backup source is device, restore source is image file. Receving data from pipe line is supported ONLY for restoring, just ignore -s option or use '-' means receive data from stdin. Output FILE. The FILE could be a image file(partclone will generate) or device depend on your action. Normanly, backup output to image file and restore output to device. Sending data to pipe line is also supported ONLY for back-up, just ignore -o option or use '-' means send data to stdout. Overwrite FILE, overwriting if exists. Creating special raw file for loop device. put special path to record partclone log information.(default /var/log/partclone.log) Continue after disk read errors. Don't check device size and free space. Using Ncurses Text User Interface. Output message as Dialog Format. Ignore filesystem check. Ignore crc check error. Force progress. put special second to different interval. Read/write buffer size (default: 1048576) Disable progress message. Set the debug level [1|2|3] Show summary of options. Show version of program. FILES /var/log/partclone.log The log file of &dhpackage; EXAMPLES restore /dev/hda1 from hda1.img and display debug information. partclone.restore -d -s hda1.img -o /dev/hda1 restore image from clonezilla(split, gzip,) with stdin source cat sda1.ext3-ptcl-img.gz.a* | gunzip -c | partclone.restore -d -s - -o /dev/sda1 restore raw image from partclone.dd partclone.dd -d -c -s /dev/sda1 -o - | partclone.restore -d -s - -o /dev/sdb1 DIAGNOSTICS The following diagnostics may be issued on stderr: &dhpackage; provides some return codes, that can be used in scripts: Code Diagnostic 0 Program exited successfully. 1 Clone or Restore seem failed. BUGS Report bugs to &dhemail; or . You can get support at http://partclone.org SEE ALSO partclone 8 , partclone.chkimg 8 , partclone.restore 8 , partclone.dd 8 , partclone.info 8
partclone-0.2.86/docs/partclone.ufs.8000066400000000000000000000000251262102574200174000ustar00rootroot00000000000000.so man8/partclone.8 partclone-0.2.86/docs/partclone.vfat.8000066400000000000000000000000251262102574200175430ustar00rootroot00000000000000.so man8/partclone.8 partclone-0.2.86/docs/partclone.vmfs.8000066400000000000000000000000251262102574200175560ustar00rootroot00000000000000.so man8/partclone.8 partclone-0.2.86/docs/partclone.vmfs3.8000066400000000000000000000000251262102574200176410ustar00rootroot00000000000000.so man8/partclone.8 partclone-0.2.86/docs/partclone.vmfs5.8000066400000000000000000000000251262102574200176430ustar00rootroot00000000000000.so man8/partclone.8 partclone-0.2.86/docs/partclone.xfs.8000066400000000000000000000000251262102574200174030ustar00rootroot00000000000000.so man8/partclone.8 partclone-0.2.86/docs/partclone.xml000066400000000000000000000434171262102574200172510ustar00rootroot00000000000000 .
will be generated. You may view the manual page with: nroff -man .
| less'. A typical entry in a Makefile or Makefile.am is: DB2MAN = /usr/share/sgml/docbookstylesheet/xsl/docbook-xsl/manpages/docbook.xsl or DB2MAN = /usr/share/xml/docbook/stylesheet/docbook-xsl/manpages/docbook.xsl XP = xsltproc -''-nonet -''-param man.charmap.use.subset "0" manpage.1: manpage.xml $(XP) $(DB2MAN) $< The xsltproc binary is found in the xsltproc package. The XSL files are in docbook-xsl. A description of the parameters you can use can be found in the docbook-xsl-doc-* packages. Please remember that if you create the nroff version in one of the debian/rules file targets (such as build), you will need to include xsltproc and docbook-xsl in your Build-Depends control field. Alternatively use the xmlto command/package. That will also automatically pull in xsltproc and docbook-xsl. Notes for using docbook2x: docbook2x-man does not automatically create the AUTHOR(S) and COPYRIGHT sections. In this case, please add them manually as ... . To disable the automatic creation of the AUTHOR(S) and COPYRIGHT sections read /usr/share/doc/docbook-xsl/doc/manpages/authors.html. This file can be found in the docbook-xsl-doc-html package. Validation can be done using: `xmllint -''-noout -''-valid manpage.xml` General documentation about man-pages and man-page-formatting: man(1), man(7), http://www.tldp.org/HOWTO/Man-Page/ --> ]> &dhtitle; &dhpackage; &dhfirstname; &dhsurname;
&dhemail;
2007 &dhusername; This manual page was written for the Debian system (and may be used by others). Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 2 or (at your option) any later version published by the Free Software Foundation. On Debian systems, the complete text of the GNU General Public License can be found in /usr/share/common-licenses/GPL.
&dhucpackage; &dhsection; &dhpackage; The utility for clone and restore a partition. &dhpackage;.[fstype] source target logfile DESCRIPTION &dhpackage;.[fstype] is a part of Partclone project. Partclone provide utilities to backup used blocks and design for higher compatibility of the file system by using existing library, e.g. e2fslibs is used to read the used block of ext2 partition. Partclone supported file system include btrfs, ext2, ext3, ext4, reiserfs, reiser4, xfs and jfs for LINUX. Also support some non-linux operation system, ex: NTFS, FAT and EXFAT(for Windows), HFS plus(APPLE MAC OS), UFS2(FreeBSD), VMFS(VMWare Vsphere) and MINIX(MINIX3). All partclone utils could be run like partclone.[fstype] is very smiliar fsck or mkfs. For example, for backup/restore hfsplus, just run partclone.hfsp File System partclone.[fstype] btrfs partclone.btrfs ext2, ext3, ext4 partclone.[ext2|ext3|ext4] reiserfs 3.5 partclone.reiserfs reiser 4 partclone.reiser4 xfs partclone.xfs ufs | ufs2 partclone.ufs jfs partclone.jfs hfs plusfs partclone.[hfs+|hfsplus] vmfs partclone.vmfs ntfs partclone.ntfs fat12, fat16, fat32 partclone.[fat12|fat16|fat32] exfat partclone.exfat minix partclone.minix f2fs partclone.f2fs OPTIONS The program follows the usual GNU command line syntax, with long options starting with two dashes (`-'). A summary of options is included below. Source FILE. The FILE could be a image file(made by partclone) or device depend on your action. Normanly, backup source is device, restore source is image file. Receving data from pipe line is supported ONLY for restoring, just ignore -s option or use '-' means receive data from stdin. Output FILE. The FILE could be a image file(partclone will generate) or device depend on your action. Normanly, backup output to image file and restore output to device. Sending data to pipe line is also supported ONLY for back-up, just ignore -o option or use '-' means send data to stdout. Overwrite FILE, overwriting if exists. Save partition to the special image format. Restore partition from the special image format. Local device to device copy on-the-fly, source and output both are device. Create GNU Ddrescue domain log file from source device Add X (in bytes) to all positions reported in the domain log file Creating special raw file for loop device. put special path to record partclone log information.(default /var/log/partclone.log) Continue after disk read errors. Don't check device size and free space. Using Ncurses Text User Interface. Output message as Dialog Format. Ignore filesystem check. Ignore crc check error. Force progress. put special second to different interval. Read/write buffer size (default: 1048576) Disable progress message. Set the debug level [1|2|3] Show summary of options. Show version of program. FILES /var/log/partclone.log The log file of &dhpackage; EXAMPLES clone /dev/hda1 to hda1.img and display debug information. partclone.ext3 -c -d -s /dev/hda1 -o hda1.img restore /dev/hda1 from hda1.img and display debug information. partclone.extfs -r -d -s hda1.img -o /dev/hda1 restore image from clonezilla(split, gzip,) with stdin source cat sda1.ext3-ptcl-img.gz.a* | gunzip -c | partclone.ext3 -d -r -s - -o /dev/sda1 DIAGNOSTICS The following diagnostics may be issued on stderr: &dhpackage; provides some return codes, that can be used in scripts: Code Diagnostic 0 Program exited successfully. 1 Clone or Restore seem failed. BUGS Report bugs to &dhemail; or . You can get support at http://partclone.org SEE ALSO partclone 8 , partclone.chkimg 8 , partclone.restore 8 , partclone.dd 8 , partclone.info 8
partclone-0.2.86/fail-mbr/000077500000000000000000000000001262102574200152705ustar00rootroot00000000000000partclone-0.2.86/fail-mbr/Makefile000066400000000000000000000347321262102574200167410ustar00rootroot00000000000000# Makefile.in generated by automake 1.15 from Makefile.am. # fail-mbr/Makefile. Generated from Makefile.in by configure. # Copyright (C) 1994-2014 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/partclone pkgincludedir = $(includedir)/partclone pkglibdir = $(libdir)/partclone pkglibexecdir = $(libexecdir)/partclone am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = x86_64-unknown-linux-gnu host_triplet = x86_64-unknown-linux-gnu subdir = fail-mbr ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/gettext.m4 \ $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_$(V)) am__v_P_ = $(am__v_P_$(AM_DEFAULT_VERBOSITY)) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_$(V)) am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_$(V)) am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(failmbrdir)" DATA = $(failmbr_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__DIST_COMMON = $(srcdir)/Makefile.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = ${SHELL} /home/partimag/dev/partclone/missing aclocal-1.15 AMTAR = $${TAR-tar} AM_DEFAULT_VERBOSITY = 1 AUTOCONF = ${SHELL} /home/partimag/dev/partclone/missing autoconf AUTOHEADER = ${SHELL} /home/partimag/dev/partclone/missing autoheader AUTOMAKE = ${SHELL} /home/partimag/dev/partclone/missing automake-1.15 AWK = gawk CC = gcc CCDEPMODE = depmode=gcc3 CFLAGS = -g -O2 -Wall CPP = gcc -E CPPFLAGS = CYGPATH_W = echo DEFS = -DHAVE_CONFIG_H DEPDIR = .deps ECHO_C = ECHO_N = -n ECHO_T = EGREP = /bin/grep -E EXEEXT = EXT2FS_CFLAGS = -I/usr/include/ext2fs -I/usr/include/et EXT2FS_LIBS = -lext2fs GMSGFMT = /usr/bin/msgfmt GMSGFMT_015 = /usr/bin/msgfmt GREP = /bin/grep INSTALL = /usr/bin/install -c INSTALL_DATA = ${INSTALL} -m 644 INSTALL_PROGRAM = ${INSTALL} INSTALL_SCRIPT = ${INSTALL} INSTALL_STRIP_PROGRAM = $(install_sh) -c -s INTLLIBS = INTL_MACOSX_LIBS = LDFLAGS = LIBICONV = -liconv LIBINTL = LIBOBJS = LIBS = -lpthread LN_S = ln -s LTLIBICONV = -liconv LTLIBINTL = LTLIBOBJS = MAKEINFO = ${SHELL} /home/partimag/dev/partclone/missing makeinfo MKDIR_P = /bin/mkdir -p MSGFMT = /usr/bin/msgfmt MSGFMT_015 = /usr/bin/msgfmt MSGMERGE = /usr/bin/msgmerge NTFS_CFLAGS = NTFS_LIBS = -lpthread -lntfs-3g OBJEXT = o ORIGINAL_CFLAGS = -g -O2 PACKAGE = partclone PACKAGE_BUGREPORT = thomas@nchc.org.tw PACKAGE_NAME = Partclone PACKAGE_STRING = Partclone 0.2.84 PACKAGE_TARNAME = partclone PACKAGE_URL = PACKAGE_VERSION = 0.2.84 PATH_SEPARATOR = : PKG_CONFIG = /usr/bin/pkg-config PKG_CONFIG_LIBDIR = PKG_CONFIG_PATH = POSUB = po RM = /bin/rm SET_MAKE = SHELL = /bin/bash STRIP = USE_NLS = yes UUID_CFLAGS = -I/usr/include/uuid UUID_LIBS = -luuid VERSION = 0.2.84 XGETTEXT = /usr/bin/xgettext XGETTEXT_015 = /usr/bin/xgettext abs_builddir = /home/partimag/dev/partclone/fail-mbr abs_srcdir = /home/partimag/dev/partclone/fail-mbr abs_top_builddir = /home/partimag/dev/partclone abs_top_srcdir = /home/partimag/dev/partclone ac_ct_CC = gcc am__include = include am__leading_dot = . am__quote = am__tar = $${TAR-tar} chof - "$$tardir" am__untar = $${TAR-tar} xf - bindir = ${exec_prefix}/bin build = x86_64-unknown-linux-gnu build_alias = build_cpu = x86_64 build_os = linux-gnu build_vendor = unknown builddir = . datadir = ${datarootdir} datarootdir = ${prefix}/share docdir = ${datarootdir}/doc/${PACKAGE_TARNAME} dvidir = ${docdir} exec_prefix = ${prefix} host = x86_64-unknown-linux-gnu host_alias = host_cpu = x86_64 host_os = linux-gnu host_vendor = unknown htmldir = ${docdir} includedir = ${prefix}/include infodir = ${datarootdir}/info install_sh = ${SHELL} /home/partimag/dev/partclone/install-sh libdir = ${exec_prefix}/lib libexecdir = ${exec_prefix}/libexec localedir = ${datarootdir}/locale localstatedir = ${prefix}/var mandir = ${datarootdir}/man mkdir_p = /bin/mkdir -p oldincludedir = /usr/include pdfdir = ${docdir} prefix = /usr/local program_transform_name = s,x,x, psdir = ${docdir} runstatedir = ${localstatedir}/run sbindir = ${exec_prefix}/sbin sharedstatedir = ${prefix}/com srcdir = . sysconfdir = ${prefix}/etc target_alias = top_build_prefix = ../ top_builddir = .. top_srcdir = .. failmbrdir = $(datadir)/partclone/ failmbr_DATA = fail-mbr.bin all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign fail-mbr/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign fail-mbr/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-failmbrDATA: $(failmbr_DATA) @$(NORMAL_INSTALL) @list='$(failmbr_DATA)'; test -n "$(failmbrdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(failmbrdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(failmbrdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(failmbrdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(failmbrdir)" || exit $$?; \ done uninstall-failmbrDATA: @$(NORMAL_UNINSTALL) @list='$(failmbr_DATA)'; test -n "$(failmbrdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(failmbrdir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(DATA) installdirs: for dir in "$(DESTDIR)$(failmbrdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-local mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic distclean-local dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-failmbrDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-failmbrDATA .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-local \ cscopelist-am ctags-am distclean distclean-generic \ distclean-local distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am \ install-failmbrDATA install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic pdf \ pdf-am ps ps-am tags-am uninstall uninstall-am \ uninstall-failmbrDATA .PRECIOUS: Makefile clean-local: rm -f *~ *.o *.image *.bin distclean-local: clean-local fail-mbr.bin: sh compile-mbr.sh # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: partclone-0.2.86/fail-mbr/Makefile.am000066400000000000000000000002471262102574200173270ustar00rootroot00000000000000failmbrdir=$(datadir)/@PACKAGE@/ failmbr_DATA = fail-mbr.bin clean-local: rm -f *~ *.o *.image *.bin distclean-local: clean-local fail-mbr.bin: sh compile-mbr.sh partclone-0.2.86/fail-mbr/Makefile.in000066400000000000000000000344041262102574200173420ustar00rootroot00000000000000# Makefile.in generated by automake 1.15 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2014 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = fail-mbr ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/gettext.m4 \ $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(failmbrdir)" DATA = $(failmbr_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__DIST_COMMON = $(srcdir)/Makefile.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXT2FS_CFLAGS = @EXT2FS_CFLAGS@ EXT2FS_LIBS = @EXT2FS_LIBS@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ LDFLAGS = @LDFLAGS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LN_S = @LN_S@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ NTFS_CFLAGS = @NTFS_CFLAGS@ NTFS_LIBS = @NTFS_LIBS@ OBJEXT = @OBJEXT@ ORIGINAL_CFLAGS = @ORIGINAL_CFLAGS@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ POSUB = @POSUB@ RM = @RM@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ USE_NLS = @USE_NLS@ UUID_CFLAGS = @UUID_CFLAGS@ UUID_LIBS = @UUID_LIBS@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ failmbrdir = $(datadir)/@PACKAGE@/ failmbr_DATA = fail-mbr.bin all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign fail-mbr/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign fail-mbr/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-failmbrDATA: $(failmbr_DATA) @$(NORMAL_INSTALL) @list='$(failmbr_DATA)'; test -n "$(failmbrdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(failmbrdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(failmbrdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(failmbrdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(failmbrdir)" || exit $$?; \ done uninstall-failmbrDATA: @$(NORMAL_UNINSTALL) @list='$(failmbr_DATA)'; test -n "$(failmbrdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(failmbrdir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(DATA) installdirs: for dir in "$(DESTDIR)$(failmbrdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-local mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic distclean-local dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-failmbrDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-failmbrDATA .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-local \ cscopelist-am ctags-am distclean distclean-generic \ distclean-local distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am \ install-failmbrDATA install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic pdf \ pdf-am ps ps-am tags-am uninstall uninstall-am \ uninstall-failmbrDATA .PRECIOUS: Makefile clean-local: rm -f *~ *.o *.image *.bin distclean-local: clean-local fail-mbr.bin: sh compile-mbr.sh # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: partclone-0.2.86/fail-mbr/README.txt000066400000000000000000000012031262102574200167620ustar00rootroot00000000000000== How to disassemble fail-mbr.bin == objdump -D -b binary -mi386 -Maddr16,data16 fail-mbr.bin > fail-mbr.src this feeds the file fail-mbr.src with opcodes. However some opcodes are irrelevant, since they are never executed. Those stand for ascii strings or space-filling zeros. == How to build fail-mbr.bin == "make" does it. The Makefile has an other target "clean" to clean the source. The file Makefile has been inspired by the build logfile of the package grub2. In that package, assembly sources are compiled once, then linked and finally stripped down. The switches for gxx and objcopy were shamelessly copied from this log file. partclone-0.2.86/fail-mbr/authors000066400000000000000000000000171262102574200166760ustar00rootroot00000000000000Georges Thomas partclone-0.2.86/fail-mbr/compile-mbr.sh000066400000000000000000000041331262102574200200330ustar00rootroot00000000000000############### compiles source file for x86 architectures ################## if dpkg-architecture -e amd64 || dpkg-architecture -e i386; then # compile the file fail-mbr.bin echo -n "Compiling: fail-mbr.S -> fail-mbr.o -> " gcc -Wall -Werror -m32 -nostdlib -o fail-mbr.o fail-mbr.S echo -n "fail-mbr.image -> " gcc -Os -Wall -W -Wshadow -Wpointer-arith -Wmissing-prototypes -Wundef -Wstrict-prototypes -g -falign-jumps=1 -falign-loops=1 -falign-functions=1 -mno-mmx -mno-sse -mno-sse2 -mno-3dnow -fno-dwarf2-cfi-asm -fno-asynchronous-unwind-tables -m32 -fno-stack-protector -mno-stack-arg-probe -Werror -Wno-trampolines -DUSE_ASCII_FAILBACK=1 -DHAVE_UNIFONT_WIDTHSPEC=1 -mrtd -mregparm=3 -fno-builtin -m32 -Wl,--build-id=none -nostdlib -Wl,-N,-S -Wl,-N -Wl,-Ttext,0x7C00 -o fail-mbr.image fail-mbr.o echo "fail-mbr.bin [Done]. " objcopy -O binary --strip-unneeded -R .note -R .comment -R .note.gnu.build-id -R .reginfo -R .rel.dyn fail-mbr.image fail-mbr.bin else echo "The architecture is not x86, so the file 'fail-mbr.bin' is not compiled" echo "Copying 'fail-mbr.bin.orig' to 'fail-mbr.bin'" cp fail-mbr.bin.orig fail-mbr.bin fi ######################### Checks the build ############################# # checks that this file does the same than the original fail-mbr echo "Checking the file:" objdump -D -b binary -mi386 -Maddr16,data16 fail-mbr.bin > f1.obj objdump -D -b binary -mi386 -Maddr16,data16 fail-mbr.bin.orig > f2.obj # the regular expression 'fail-mbr|---|xor %ax,%ax|^[a-f0-9]*$' is used # to reject lines which contain either: # - the name of the file, "fail-mbr" # - a line separator output by diff, "---" # - the OP code "xor %ax,%ax" which may begin by 0x31 or 0x33 # - a numerical offset output by diff, ^[a-f0-9]*$ report=$(diff f1.obj f2.obj | grep -Ev 'fail-mbr|---|xor %ax,%ax|^[a-f0-9]*$') rm f1.obj f2.obj if [ -n "$report" ]; then echo "files fail-mbr.bin and fail-mbr.bin.orig differ significantly:" diff f1.obj f2.obj exit 1 else echo "'fail-mbr.bin' and 'fail-mbr.bin.orig' have no significant differences." exit 0 fi partclone-0.2.86/fail-mbr/fail-mbr.S000066400000000000000000000043611262102574200171110ustar00rootroot00000000000000/* -*-Asm-*- */ /* * fail-mbr. This file is part of the project DRBL * The code has been strongly inspired by the file * grub-core/boot/i386/pc/boot.S (package grub2) and by the file * fail-mbr.bin which had been written with an hexadecimal editor by * Orgad Shaneh . * Copyright (C) 2012 Georges Khaznadar * * DRBL is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * DRBL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with DRBL. If not, see . */ .file "fail-mbr.S" .text /* Tell GAS to generate 16-bit instructions so that this code works in real mode. */ .code16 .globl _start _start: /* * _start is loaded at 0x7c00 and is jumped to with CS:IP 0:0x7c00 */ .set real_start, 0x7c00 /* * Beginning of the sector is compatible with the FAT/HPFS BIOS * parameter block. */ jmp after_signature signature: .ascii "OCS Dummy MBR" nop after_signature: /* general setup */ xor %ax, %ax /* zero in ax */ push %ax pop %ds /* zero in ds */ mov $(failure_msg + real_start - _start), %si /* point to the message */ start_msg1: lods %ds:(%si),%al /* get one char and increment the pointer */ cmp $0x0, %al /* is the cstring finished? */ je end_msg1 mov $0x7, %bx /* page 0, color 7 (only in graphics mode) */ mov $0x1, %cx /* probably not relevant is it a bug? */ mov $0xe, %ah /* prepare a call to Teletype output */ int $0x10 /* BIOS call */ jmp start_msg1 end_msg1: mov $0x2, %ah /* prepare a call to Set cursor position */ mov $0x100, %dx /* row 0, column 1 */ int $0x10 /* BIOS call */ wait_forever: cmp $0x0,%al je wait_forever failure_msg: .ascii "Image loading failure. Reload image!\0" /* filling with zeros to match the length of another mbr file */ . = _start + 0x1bd .byte 0x0 partclone-0.2.86/fail-mbr/fail-mbr.bin.orig000066400000000000000000000006761262102574200204230ustar00rootroot00000000000000ëOCS Dummy MBR3ÀP¾3|¬<t »¹´Íëï´ºÍ<tüImage loading failure. Reload image!partclone-0.2.86/gitlog-to-changelog000066400000000000000000000115601262102574200173570ustar00rootroot00000000000000#!/usr/bin/perl # Convert git log output to ChangeLog format. my $VERSION = '2008-12-21 12:07'; # UTC # The definition above must lie within the first 8 lines in order # for the Emacs time-stamp write hook (at end) to update it. # If you change this file with Emacs, please let the write hook # do its job. Otherwise, update this string manually. # Copyright (C) 2008 Free Software Foundation, Inc. # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program. If not, see . # Written by Jim Meyering use strict; use warnings; use Getopt::Long; use POSIX qw(strftime); (my $ME = $0) =~ s|.*/||; # use File::Coda; # http://meyering.net/code/Coda/ END { defined fileno STDOUT or return; close STDOUT and return; warn "$ME: failed to close standard output: $!\n"; $? ||= 1; } sub usage ($) { my ($exit_code) = @_; my $STREAM = ($exit_code == 0 ? *STDOUT : *STDERR); if ($exit_code != 0) { print $STREAM "Try `$ME --help' for more information.\n"; } else { print $STREAM < ChangeLog $ME -- -n 5 foo > last-5-commits-to-branch-foo EOF } exit $exit_code; } # If the string $S is a well-behaved file name, simply return it. # If it contains white space, quotes, etc., quote it, and return the new string. sub shell_quote($) { my ($s) = @_; if ($s =~ m![^\w+/.,-]!) { # Convert each single quote to '\'' $s =~ s/\'/\'\\\'\'/g; # Then single quote the string. $s = "'$s'"; } return $s; } sub quoted_cmd(@) { return join (' ', map {shell_quote $_} @_); } { my $since_date = '1970-01-01 UTC'; GetOptions ( help => sub { usage 0 }, version => sub { print "$ME version $VERSION\n"; exit }, 'since=s' => \$since_date, ) or usage 1; my @cmd = (qw (git log --log-size), "--since=$since_date", '--pretty=format:%ct %an <%ae>%n%n%s%n%b%n', @ARGV); open PIPE, '-|', @cmd or die ("$ME: failed to run `". quoted_cmd (@cmd) ."': $!\n" . "(Is your Git too old? Version 1.5.1 or later is required.)\n"); my $prev_date_line = ''; while (1) { defined (my $in = ) or last; $in =~ /^log size (\d+)$/ or die "$ME:$.: Invalid line (expected log size):\n$in"; my $log_nbytes = $1; my $log; my $n_read = read PIPE, $log, $log_nbytes; $n_read == $log_nbytes or die "$ME:$.: unexpected EOF\n"; my @line = split "\n", $log; my $author_line = shift @line; defined $author_line or die "$ME:$.: unexpected EOF\n"; $author_line =~ /^(\d+) (.*>)$/ or die "$ME:$.: Invalid line " . "(expected date/author/email):\n$author_line\n"; my $date_line = sprintf "%s $2\n", strftime ("%F", localtime ($1)); # If this line would be the same as the previous date/name/email # line, then arrange not to print it. if ($date_line ne $prev_date_line) { $prev_date_line eq '' or print "\n"; print $date_line; } $prev_date_line = $date_line; # Omit "Signed-off-by..." lines. @line = grep !/^Signed-off-by: .*>$/, @line; # Remove leading and trailing blank lines. while ($line[0] =~ /^\s*$/) { shift @line; } while ($line[$#line] =~ /^\s*$/) { pop @line; } # Prefix each non-empty line with a TAB. @line = map { length $_ ? "\t$_" : '' } @line; print "\n", join ("\n", @line), "\n"; defined ($in = ) or last; $in ne "\n" and die "$ME:$.: unexpected line:\n$in"; } close PIPE or die "$ME: error closing pipe from " . quoted_cmd (@cmd) . "\n"; # FIXME-someday: include $PROCESS_STATUS in the diagnostic } # Local Variables: # indent-tabs-mode: nil # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "my $VERSION = '" # time-stamp-format: "%:y-%02m-%02d %02H:%02M" # time-stamp-time-zone: "UTC" # time-stamp-end: "'; # UTC" # End: partclone-0.2.86/install-sh000077500000000000000000000345231262102574200156120ustar00rootroot00000000000000#!/bin/sh # install - install a program, script, or datafile scriptversion=2013-12-25.23; # UTC # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # Calling this script install-sh is preferred over install.sh, to prevent # 'make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. tab=' ' nl=' ' IFS=" $tab$nl" # Set DOITPROG to "echo" to test this script. doit=${DOITPROG-} doit_exec=${doit:-exec} # Put in absolute file names if you don't have them in your path; # or use environment vars. chgrpprog=${CHGRPPROG-chgrp} chmodprog=${CHMODPROG-chmod} chownprog=${CHOWNPROG-chown} cmpprog=${CMPPROG-cmp} cpprog=${CPPROG-cp} mkdirprog=${MKDIRPROG-mkdir} mvprog=${MVPROG-mv} rmprog=${RMPROG-rm} stripprog=${STRIPPROG-strip} posix_mkdir= # Desired mode of installed file. mode=0755 chgrpcmd= chmodcmd=$chmodprog chowncmd= mvcmd=$mvprog rmcmd="$rmprog -f" stripcmd= src= dst= dir_arg= dst_arg= copy_on_change=false is_target_a_directory=possibly usage="\ Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -d DIRECTORIES... In the 1st form, copy SRCFILE to DSTFILE. In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. In the 4th, create DIRECTORIES. Options: --help display this help and exit. --version display version info and exit. -c (ignored) -C install only if different (preserve the last data modification time) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. -s $stripprog installed files. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG " while test $# -ne 0; do case $1 in -c) ;; -C) copy_on_change=true;; -d) dir_arg=true;; -g) chgrpcmd="$chgrpprog $2" shift;; --help) echo "$usage"; exit $?;; -m) mode=$2 case $mode in *' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*) echo "$0: invalid mode: $mode" >&2 exit 1;; esac shift;; -o) chowncmd="$chownprog $2" shift;; -s) stripcmd=$stripprog;; -t) is_target_a_directory=always dst_arg=$2 # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac shift;; -T) is_target_a_directory=never;; --version) echo "$0 $scriptversion"; exit $?;; --) shift break;; -*) echo "$0: invalid option: $1" >&2 exit 1;; *) break;; esac shift done # We allow the use of options -d and -T together, by making -d # take the precedence; this is for compatibility with GNU install. if test -n "$dir_arg"; then if test -n "$dst_arg"; then echo "$0: target directory not allowed when installing a directory." >&2 exit 1 fi fi if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dst_arg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dst_arg" shift # fnord fi shift # arg dst_arg=$arg # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac done fi if test $# -eq 0; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call 'install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi if test -z "$dir_arg"; then if test $# -gt 1 || test "$is_target_a_directory" = always; then if test ! -d "$dst_arg"; then echo "$0: $dst_arg: Is not a directory." >&2 exit 1 fi fi fi if test -z "$dir_arg"; then do_exit='(exit $ret); exit $ret' trap "ret=129; $do_exit" 1 trap "ret=130; $do_exit" 2 trap "ret=141; $do_exit" 13 trap "ret=143; $do_exit" 15 # Set umask so as not to create temps with too-generous modes. # However, 'strip' requires both read and write access to temps. case $mode in # Optimize common cases. *644) cp_umask=133;; *755) cp_umask=22;; *[0-7]) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw='% 200' fi cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; *) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw=,u+rw fi cp_umask=$mode$u_plus_rw;; esac fi for src do # Protect names problematic for 'test' and other utilities. case $src in -* | [=\(\)!]) src=./$src;; esac if test -n "$dir_arg"; then dst=$src dstdir=$dst test -d "$dstdir" dstdir_status=$? else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dst_arg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dst_arg # If destination is a directory, append the input filename; won't work # if double slashes aren't ignored. if test -d "$dst"; then if test "$is_target_a_directory" = never; then echo "$0: $dst_arg: Is a directory" >&2 exit 1 fi dstdir=$dst dst=$dstdir/`basename "$src"` dstdir_status=0 else dstdir=`dirname "$dst"` test -d "$dstdir" dstdir_status=$? fi fi obsolete_mkdir_used=false if test $dstdir_status != 0; then case $posix_mkdir in '') # Create intermediate dirs using mode 755 as modified by the umask. # This is like FreeBSD 'install' as of 1997-10-28. umask=`umask` case $stripcmd.$umask in # Optimize common cases. *[2367][2367]) mkdir_umask=$umask;; .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; *[0-7]) mkdir_umask=`expr $umask + 22 \ - $umask % 100 % 40 + $umask % 20 \ - $umask % 10 % 4 + $umask % 2 `;; *) mkdir_umask=$umask,go-w;; esac # With -d, create the new directory with the user-specified mode. # Otherwise, rely on $mkdir_umask. if test -n "$dir_arg"; then mkdir_mode=-m$mode else mkdir_mode= fi posix_mkdir=false case $umask in *[123567][0-7][0-7]) # POSIX mkdir -p sets u+wx bits regardless of umask, which # is incompatible with FreeBSD 'install' when (umask & 300) != 0. ;; *) tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 if (umask $mkdir_umask && exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 then if test -z "$dir_arg" || { # Check for POSIX incompatibilities with -m. # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or # other-writable bit of parent directory when it shouldn't. # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. ls_ld_tmpdir=`ls -ld "$tmpdir"` case $ls_ld_tmpdir in d????-?r-*) different_mode=700;; d????-?--*) different_mode=755;; *) false;; esac && $mkdirprog -m$different_mode -p -- "$tmpdir" && { ls_ld_tmpdir_1=`ls -ld "$tmpdir"` test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" } } then posix_mkdir=: fi rmdir "$tmpdir/d" "$tmpdir" else # Remove any dirs left behind by ancient mkdir implementations. rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null fi trap '' 0;; esac;; esac if $posix_mkdir && ( umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ) then : else # The umask is ridiculous, or mkdir does not conform to POSIX, # or it failed possibly due to a race condition. Create the # directory the slow way, step by step, checking for races as we go. case $dstdir in /*) prefix='/';; [-=\(\)!]*) prefix='./';; *) prefix='';; esac oIFS=$IFS IFS=/ set -f set fnord $dstdir shift set +f IFS=$oIFS prefixes= for d do test X"$d" = X && continue prefix=$prefix$d if test -d "$prefix"; then prefixes= else if $posix_mkdir; then (umask=$mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break # Don't fail if two instances are running concurrently. test -d "$prefix" || exit 1 else case $prefix in *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; *) qprefix=$prefix;; esac prefixes="$prefixes '$qprefix'" fi fi prefix=$prefix/ done if test -n "$prefixes"; then # Don't fail if two instances are running concurrently. (umask $mkdir_umask && eval "\$doit_exec \$mkdirprog $prefixes") || test -d "$dstdir" || exit 1 obsolete_mkdir_used=true fi fi fi if test -n "$dir_arg"; then { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 else # Make a couple of temp file names in the proper directory. dsttmp=$dstdir/_inst.$$_ rmtmp=$dstdir/_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 # Copy the file name to the temp name. (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && # and set any options; do chmod last to preserve setuid bits. # # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && # If -C, don't bother to copy if it wouldn't change the file. if $copy_on_change && old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && set -f && set X $old && old=:$2:$4:$5:$6 && set X $new && new=:$2:$4:$5:$6 && set +f && test "$old" = "$new" && $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 then rm -f "$dsttmp" else # Rename the file to the real destination. $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || # The rename failed, perhaps because mv can't rename something else # to itself, or perhaps because mv is so ancient that it does not # support -f. { # Now remove or move aside any old file at destination location. # We try this two ways since rm can't unlink itself on some # systems and the destination file might be busy for other # reasons. In this case, the final cleanup might fail but the new # file should still install successfully. { test ! -f "$dst" || $doit $rmcmd -f "$dst" 2>/dev/null || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } } || { echo "$0: cannot unlink or rename $dst" >&2 (exit 1); exit 1 } } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dst" } fi || exit 1 trap '' 0 fi done # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: partclone-0.2.86/m4/000077500000000000000000000000001262102574200141175ustar00rootroot00000000000000partclone-0.2.86/m4/ChangeLog000066400000000000000000000006351262102574200156750ustar00rootroot000000000000002007-11-01 gettextize * gettext.m4: New file, from gettext-0.16.1. * iconv.m4: New file, from gettext-0.16.1. * lib-ld.m4: New file, from gettext-0.16.1. * lib-link.m4: New file, from gettext-0.16.1. * lib-prefix.m4: New file, from gettext-0.16.1. * nls.m4: New file, from gettext-0.16.1. * po.m4: New file, from gettext-0.16.1. * progtest.m4: New file, from gettext-0.16.1. partclone-0.2.86/m4/gettext.m4000066400000000000000000000377321262102574200160610ustar00rootroot00000000000000# gettext.m4 serial 59 (gettext-0.16.1) dnl Copyright (C) 1995-2006 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl dnl This file can can be used in projects which are not available under dnl the GNU General Public License or the GNU Library General Public dnl License but which still want to provide support for the GNU gettext dnl functionality. dnl Please note that the actual code of the GNU gettext library is covered dnl by the GNU Library General Public License, and the rest of the GNU dnl gettext package package is covered by the GNU General Public License. dnl They are *not* in the public domain. dnl Authors: dnl Ulrich Drepper , 1995-2000. dnl Bruno Haible , 2000-2006. dnl Macro to add for using GNU gettext. dnl Usage: AM_GNU_GETTEXT([INTLSYMBOL], [NEEDSYMBOL], [INTLDIR]). dnl INTLSYMBOL can be one of 'external', 'no-libtool', 'use-libtool'. The dnl default (if it is not specified or empty) is 'no-libtool'. dnl INTLSYMBOL should be 'external' for packages with no intl directory, dnl and 'no-libtool' or 'use-libtool' for packages with an intl directory. dnl If INTLSYMBOL is 'use-libtool', then a libtool library dnl $(top_builddir)/intl/libintl.la will be created (shared and/or static, dnl depending on --{enable,disable}-{shared,static} and on the presence of dnl AM-DISABLE-SHARED). If INTLSYMBOL is 'no-libtool', a static library dnl $(top_builddir)/intl/libintl.a will be created. dnl If NEEDSYMBOL is specified and is 'need-ngettext', then GNU gettext dnl implementations (in libc or libintl) without the ngettext() function dnl will be ignored. If NEEDSYMBOL is specified and is dnl 'need-formatstring-macros', then GNU gettext implementations that don't dnl support the ISO C 99 formatstring macros will be ignored. dnl INTLDIR is used to find the intl libraries. If empty, dnl the value `$(top_builddir)/intl/' is used. dnl dnl The result of the configuration is one of three cases: dnl 1) GNU gettext, as included in the intl subdirectory, will be compiled dnl and used. dnl Catalog format: GNU --> install in $(datadir) dnl Catalog extension: .mo after installation, .gmo in source tree dnl 2) GNU gettext has been found in the system's C library. dnl Catalog format: GNU --> install in $(datadir) dnl Catalog extension: .mo after installation, .gmo in source tree dnl 3) No internationalization, always use English msgid. dnl Catalog format: none dnl Catalog extension: none dnl If INTLSYMBOL is 'external', only cases 2 and 3 can occur. dnl The use of .gmo is historical (it was needed to avoid overwriting the dnl GNU format catalogs when building on a platform with an X/Open gettext), dnl but we keep it in order not to force irrelevant filename changes on the dnl maintainers. dnl AC_DEFUN([AM_GNU_GETTEXT], [ dnl Argument checking. ifelse([$1], [], , [ifelse([$1], [external], , [ifelse([$1], [no-libtool], , [ifelse([$1], [use-libtool], , [errprint([ERROR: invalid first argument to AM_GNU_GETTEXT ])])])])]) ifelse([$2], [], , [ifelse([$2], [need-ngettext], , [ifelse([$2], [need-formatstring-macros], , [errprint([ERROR: invalid second argument to AM_GNU_GETTEXT ])])])]) define([gt_included_intl], ifelse([$1], [external], ifdef([AM_GNU_GETTEXT_][INTL_SUBDIR], [yes], [no]), [yes])) define([gt_libtool_suffix_prefix], ifelse([$1], [use-libtool], [l], [])) gt_NEEDS_INIT AM_GNU_GETTEXT_NEED([$2]) AC_REQUIRE([AM_PO_SUBDIRS])dnl ifelse(gt_included_intl, yes, [ AC_REQUIRE([AM_INTL_SUBDIR])dnl ]) dnl Prerequisites of AC_LIB_LINKFLAGS_BODY. AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) AC_REQUIRE([AC_LIB_RPATH]) dnl Sometimes libintl requires libiconv, so first search for libiconv. dnl Ideally we would do this search only after the dnl if test "$USE_NLS" = "yes"; then dnl if { eval "gt_val=\$$gt_func_gnugettext_libc"; test "$gt_val" != "yes"; }; then dnl tests. But if configure.in invokes AM_ICONV after AM_GNU_GETTEXT dnl the configure script would need to contain the same shell code dnl again, outside any 'if'. There are two solutions: dnl - Invoke AM_ICONV_LINKFLAGS_BODY here, outside any 'if'. dnl - Control the expansions in more detail using AC_PROVIDE_IFELSE. dnl Since AC_PROVIDE_IFELSE is only in autoconf >= 2.52 and not dnl documented, we avoid it. ifelse(gt_included_intl, yes, , [ AC_REQUIRE([AM_ICONV_LINKFLAGS_BODY]) ]) dnl Sometimes, on MacOS X, libintl requires linking with CoreFoundation. gt_INTL_MACOSX dnl Set USE_NLS. AC_REQUIRE([AM_NLS]) ifelse(gt_included_intl, yes, [ BUILD_INCLUDED_LIBINTL=no USE_INCLUDED_LIBINTL=no ]) LIBINTL= LTLIBINTL= POSUB= dnl Add a version number to the cache macros. case " $gt_needs " in *" need-formatstring-macros "*) gt_api_version=3 ;; *" need-ngettext "*) gt_api_version=2 ;; *) gt_api_version=1 ;; esac gt_func_gnugettext_libc="gt_cv_func_gnugettext${gt_api_version}_libc" gt_func_gnugettext_libintl="gt_cv_func_gnugettext${gt_api_version}_libintl" dnl If we use NLS figure out what method if test "$USE_NLS" = "yes"; then gt_use_preinstalled_gnugettext=no ifelse(gt_included_intl, yes, [ AC_MSG_CHECKING([whether included gettext is requested]) AC_ARG_WITH(included-gettext, [ --with-included-gettext use the GNU gettext library included here], nls_cv_force_use_gnu_gettext=$withval, nls_cv_force_use_gnu_gettext=no) AC_MSG_RESULT($nls_cv_force_use_gnu_gettext) nls_cv_use_gnu_gettext="$nls_cv_force_use_gnu_gettext" if test "$nls_cv_force_use_gnu_gettext" != "yes"; then ]) dnl User does not insist on using GNU NLS library. Figure out what dnl to use. If GNU gettext is available we use this. Else we have dnl to fall back to GNU NLS library. if test $gt_api_version -ge 3; then gt_revision_test_code=' #ifndef __GNU_GETTEXT_SUPPORTED_REVISION #define __GNU_GETTEXT_SUPPORTED_REVISION(major) ((major) == 0 ? 0 : -1) #endif changequote(,)dnl typedef int array [2 * (__GNU_GETTEXT_SUPPORTED_REVISION(0) >= 1) - 1]; changequote([,])dnl ' else gt_revision_test_code= fi if test $gt_api_version -ge 2; then gt_expression_test_code=' + * ngettext ("", "", 0)' else gt_expression_test_code= fi AC_CACHE_CHECK([for GNU gettext in libc], [$gt_func_gnugettext_libc], [AC_TRY_LINK([#include $gt_revision_test_code extern int _nl_msg_cat_cntr; extern int *_nl_domain_bindings;], [bindtextdomain ("", ""); return * gettext ("")$gt_expression_test_code + _nl_msg_cat_cntr + *_nl_domain_bindings], [eval "$gt_func_gnugettext_libc=yes"], [eval "$gt_func_gnugettext_libc=no"])]) if { eval "gt_val=\$$gt_func_gnugettext_libc"; test "$gt_val" != "yes"; }; then dnl Sometimes libintl requires libiconv, so first search for libiconv. ifelse(gt_included_intl, yes, , [ AM_ICONV_LINK ]) dnl Search for libintl and define LIBINTL, LTLIBINTL and INCINTL dnl accordingly. Don't use AC_LIB_LINKFLAGS_BODY([intl],[iconv]) dnl because that would add "-liconv" to LIBINTL and LTLIBINTL dnl even if libiconv doesn't exist. AC_LIB_LINKFLAGS_BODY([intl]) AC_CACHE_CHECK([for GNU gettext in libintl], [$gt_func_gnugettext_libintl], [gt_save_CPPFLAGS="$CPPFLAGS" CPPFLAGS="$CPPFLAGS $INCINTL" gt_save_LIBS="$LIBS" LIBS="$LIBS $LIBINTL" dnl Now see whether libintl exists and does not depend on libiconv. AC_TRY_LINK([#include $gt_revision_test_code extern int _nl_msg_cat_cntr; extern #ifdef __cplusplus "C" #endif const char *_nl_expand_alias (const char *);], [bindtextdomain ("", ""); return * gettext ("")$gt_expression_test_code + _nl_msg_cat_cntr + *_nl_expand_alias ("")], [eval "$gt_func_gnugettext_libintl=yes"], [eval "$gt_func_gnugettext_libintl=no"]) dnl Now see whether libintl exists and depends on libiconv. if { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" != yes; } && test -n "$LIBICONV"; then LIBS="$LIBS $LIBICONV" AC_TRY_LINK([#include $gt_revision_test_code extern int _nl_msg_cat_cntr; extern #ifdef __cplusplus "C" #endif const char *_nl_expand_alias (const char *);], [bindtextdomain ("", ""); return * gettext ("")$gt_expression_test_code + _nl_msg_cat_cntr + *_nl_expand_alias ("")], [LIBINTL="$LIBINTL $LIBICONV" LTLIBINTL="$LTLIBINTL $LTLIBICONV" eval "$gt_func_gnugettext_libintl=yes" ]) fi CPPFLAGS="$gt_save_CPPFLAGS" LIBS="$gt_save_LIBS"]) fi dnl If an already present or preinstalled GNU gettext() is found, dnl use it. But if this macro is used in GNU gettext, and GNU dnl gettext is already preinstalled in libintl, we update this dnl libintl. (Cf. the install rule in intl/Makefile.in.) if { eval "gt_val=\$$gt_func_gnugettext_libc"; test "$gt_val" = "yes"; } \ || { { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" = "yes"; } \ && test "$PACKAGE" != gettext-runtime \ && test "$PACKAGE" != gettext-tools; }; then gt_use_preinstalled_gnugettext=yes else dnl Reset the values set by searching for libintl. LIBINTL= LTLIBINTL= INCINTL= fi ifelse(gt_included_intl, yes, [ if test "$gt_use_preinstalled_gnugettext" != "yes"; then dnl GNU gettext is not found in the C library. dnl Fall back on included GNU gettext library. nls_cv_use_gnu_gettext=yes fi fi if test "$nls_cv_use_gnu_gettext" = "yes"; then dnl Mark actions used to generate GNU NLS library. BUILD_INCLUDED_LIBINTL=yes USE_INCLUDED_LIBINTL=yes LIBINTL="ifelse([$3],[],\${top_builddir}/intl,[$3])/libintl.[]gt_libtool_suffix_prefix[]a $LIBICONV $LIBTHREAD" LTLIBINTL="ifelse([$3],[],\${top_builddir}/intl,[$3])/libintl.[]gt_libtool_suffix_prefix[]a $LTLIBICONV $LTLIBTHREAD" LIBS=`echo " $LIBS " | sed -e 's/ -lintl / /' -e 's/^ //' -e 's/ $//'` fi CATOBJEXT= if test "$gt_use_preinstalled_gnugettext" = "yes" \ || test "$nls_cv_use_gnu_gettext" = "yes"; then dnl Mark actions to use GNU gettext tools. CATOBJEXT=.gmo fi ]) if test -n "$INTL_MACOSX_LIBS"; then if test "$gt_use_preinstalled_gnugettext" = "yes" \ || test "$nls_cv_use_gnu_gettext" = "yes"; then dnl Some extra flags are needed during linking. LIBINTL="$LIBINTL $INTL_MACOSX_LIBS" LTLIBINTL="$LTLIBINTL $INTL_MACOSX_LIBS" fi fi if test "$gt_use_preinstalled_gnugettext" = "yes" \ || test "$nls_cv_use_gnu_gettext" = "yes"; then AC_DEFINE(ENABLE_NLS, 1, [Define to 1 if translation of program messages to the user's native language is requested.]) else USE_NLS=no fi fi AC_MSG_CHECKING([whether to use NLS]) AC_MSG_RESULT([$USE_NLS]) if test "$USE_NLS" = "yes"; then AC_MSG_CHECKING([where the gettext function comes from]) if test "$gt_use_preinstalled_gnugettext" = "yes"; then if { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" = "yes"; }; then gt_source="external libintl" else gt_source="libc" fi else gt_source="included intl directory" fi AC_MSG_RESULT([$gt_source]) fi if test "$USE_NLS" = "yes"; then if test "$gt_use_preinstalled_gnugettext" = "yes"; then if { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" = "yes"; }; then AC_MSG_CHECKING([how to link with libintl]) AC_MSG_RESULT([$LIBINTL]) AC_LIB_APPENDTOVAR([CPPFLAGS], [$INCINTL]) fi dnl For backward compatibility. Some packages may be using this. AC_DEFINE(HAVE_GETTEXT, 1, [Define if the GNU gettext() function is already present or preinstalled.]) AC_DEFINE(HAVE_DCGETTEXT, 1, [Define if the GNU dcgettext() function is already present or preinstalled.]) fi dnl We need to process the po/ directory. POSUB=po fi ifelse(gt_included_intl, yes, [ dnl If this is used in GNU gettext we have to set BUILD_INCLUDED_LIBINTL dnl to 'yes' because some of the testsuite requires it. if test "$PACKAGE" = gettext-runtime || test "$PACKAGE" = gettext-tools; then BUILD_INCLUDED_LIBINTL=yes fi dnl Make all variables we use known to autoconf. AC_SUBST(BUILD_INCLUDED_LIBINTL) AC_SUBST(USE_INCLUDED_LIBINTL) AC_SUBST(CATOBJEXT) dnl For backward compatibility. Some configure.ins may be using this. nls_cv_header_intl= nls_cv_header_libgt= dnl For backward compatibility. Some Makefiles may be using this. DATADIRNAME=share AC_SUBST(DATADIRNAME) dnl For backward compatibility. Some Makefiles may be using this. INSTOBJEXT=.mo AC_SUBST(INSTOBJEXT) dnl For backward compatibility. Some Makefiles may be using this. GENCAT=gencat AC_SUBST(GENCAT) dnl For backward compatibility. Some Makefiles may be using this. INTLOBJS= if test "$USE_INCLUDED_LIBINTL" = yes; then INTLOBJS="\$(GETTOBJS)" fi AC_SUBST(INTLOBJS) dnl Enable libtool support if the surrounding package wishes it. INTL_LIBTOOL_SUFFIX_PREFIX=gt_libtool_suffix_prefix AC_SUBST(INTL_LIBTOOL_SUFFIX_PREFIX) ]) dnl For backward compatibility. Some Makefiles may be using this. INTLLIBS="$LIBINTL" AC_SUBST(INTLLIBS) dnl Make all documented variables known to autoconf. AC_SUBST(LIBINTL) AC_SUBST(LTLIBINTL) AC_SUBST(POSUB) ]) dnl Checks for special options needed on MacOS X. dnl Defines INTL_MACOSX_LIBS. AC_DEFUN([gt_INTL_MACOSX], [ dnl Check for API introduced in MacOS X 10.2. AC_CACHE_CHECK([for CFPreferencesCopyAppValue], gt_cv_func_CFPreferencesCopyAppValue, [gt_save_LIBS="$LIBS" LIBS="$LIBS -Wl,-framework -Wl,CoreFoundation" AC_TRY_LINK([#include ], [CFPreferencesCopyAppValue(NULL, NULL)], [gt_cv_func_CFPreferencesCopyAppValue=yes], [gt_cv_func_CFPreferencesCopyAppValue=no]) LIBS="$gt_save_LIBS"]) if test $gt_cv_func_CFPreferencesCopyAppValue = yes; then AC_DEFINE([HAVE_CFPREFERENCESCOPYAPPVALUE], 1, [Define to 1 if you have the MacOS X function CFPreferencesCopyAppValue in the CoreFoundation framework.]) fi dnl Check for API introduced in MacOS X 10.3. AC_CACHE_CHECK([for CFLocaleCopyCurrent], gt_cv_func_CFLocaleCopyCurrent, [gt_save_LIBS="$LIBS" LIBS="$LIBS -Wl,-framework -Wl,CoreFoundation" AC_TRY_LINK([#include ], [CFLocaleCopyCurrent();], [gt_cv_func_CFLocaleCopyCurrent=yes], [gt_cv_func_CFLocaleCopyCurrent=no]) LIBS="$gt_save_LIBS"]) if test $gt_cv_func_CFLocaleCopyCurrent = yes; then AC_DEFINE([HAVE_CFLOCALECOPYCURRENT], 1, [Define to 1 if you have the MacOS X function CFLocaleCopyCurrent in the CoreFoundation framework.]) fi INTL_MACOSX_LIBS= if test $gt_cv_func_CFPreferencesCopyAppValue = yes || test $gt_cv_func_CFLocaleCopyCurrent = yes; then INTL_MACOSX_LIBS="-Wl,-framework -Wl,CoreFoundation" fi AC_SUBST([INTL_MACOSX_LIBS]) ]) dnl gt_NEEDS_INIT ensures that the gt_needs variable is initialized. m4_define([gt_NEEDS_INIT], [ m4_divert_text([DEFAULTS], [gt_needs=]) m4_define([gt_NEEDS_INIT], []) ]) dnl Usage: AM_GNU_GETTEXT_NEED([NEEDSYMBOL]) AC_DEFUN([AM_GNU_GETTEXT_NEED], [ m4_divert_text([INIT_PREPARE], [gt_needs="$gt_needs $1"]) ]) dnl Usage: AM_GNU_GETTEXT_VERSION([gettext-version]) AC_DEFUN([AM_GNU_GETTEXT_VERSION], []) partclone-0.2.86/m4/iconv.m4000066400000000000000000000064261262102574200155070ustar00rootroot00000000000000# iconv.m4 serial AM4 (gettext-0.11.3) dnl Copyright (C) 2000-2002 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Bruno Haible. AC_DEFUN([AM_ICONV_LINKFLAGS_BODY], [ dnl Prerequisites of AC_LIB_LINKFLAGS_BODY. AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) AC_REQUIRE([AC_LIB_RPATH]) dnl Search for libiconv and define LIBICONV, LTLIBICONV and INCICONV dnl accordingly. AC_LIB_LINKFLAGS_BODY([iconv]) ]) AC_DEFUN([AM_ICONV_LINK], [ dnl Some systems have iconv in libc, some have it in libiconv (OSF/1 and dnl those with the standalone portable GNU libiconv installed). dnl Search for libiconv and define LIBICONV, LTLIBICONV and INCICONV dnl accordingly. AC_REQUIRE([AM_ICONV_LINKFLAGS_BODY]) dnl Add $INCICONV to CPPFLAGS before performing the following checks, dnl because if the user has installed libiconv and not disabled its use dnl via --without-libiconv-prefix, he wants to use it. The first dnl AC_TRY_LINK will then fail, the second AC_TRY_LINK will succeed. am_save_CPPFLAGS="$CPPFLAGS" AC_LIB_APPENDTOVAR([CPPFLAGS], [$INCICONV]) AC_CACHE_CHECK(for iconv, am_cv_func_iconv, [ am_cv_func_iconv="no, consider installing GNU libiconv" am_cv_lib_iconv=no AC_TRY_LINK([#include #include ], [iconv_t cd = iconv_open("",""); iconv(cd,NULL,NULL,NULL,NULL); iconv_close(cd);], am_cv_func_iconv=yes) if test "$am_cv_func_iconv" != yes; then am_save_LIBS="$LIBS" LIBS="$LIBS $LIBICONV" AC_TRY_LINK([#include #include ], [iconv_t cd = iconv_open("",""); iconv(cd,NULL,NULL,NULL,NULL); iconv_close(cd);], am_cv_lib_iconv=yes am_cv_func_iconv=yes) LIBS="$am_save_LIBS" fi ]) if test "$am_cv_func_iconv" = yes; then AC_DEFINE(HAVE_ICONV, 1, [Define if you have the iconv() function.]) fi if test "$am_cv_lib_iconv" = yes; then AC_MSG_CHECKING([how to link with libiconv]) AC_MSG_RESULT([$LIBICONV]) else dnl If $LIBICONV didn't lead to a usable library, we don't need $INCICONV dnl either. CPPFLAGS="$am_save_CPPFLAGS" LIBICONV= LTLIBICONV= fi AC_SUBST(LIBICONV) AC_SUBST(LTLIBICONV) ]) AC_DEFUN([AM_ICONV], [ AM_ICONV_LINK if test "$am_cv_func_iconv" = yes; then AC_MSG_CHECKING([for iconv declaration]) AC_CACHE_VAL(am_cv_proto_iconv, [ AC_TRY_COMPILE([ #include #include extern #ifdef __cplusplus "C" #endif #if defined(__STDC__) || defined(__cplusplus) size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft); #else size_t iconv(); #endif ], [], am_cv_proto_iconv_arg1="", am_cv_proto_iconv_arg1="const") am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);"]) am_cv_proto_iconv=`echo "[$]am_cv_proto_iconv" | tr -s ' ' | sed -e 's/( /(/'` AC_MSG_RESULT([$]{ac_t:- }[$]am_cv_proto_iconv) AC_DEFINE_UNQUOTED(ICONV_CONST, $am_cv_proto_iconv_arg1, [Define as const if the declaration of iconv() needs const.]) fi ]) partclone-0.2.86/m4/lib-ld.m4000066400000000000000000000065311262102574200155310ustar00rootroot00000000000000# lib-ld.m4 serial 3 (gettext-0.13) dnl Copyright (C) 1996-2003 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl Subroutines of libtool.m4, dnl with replacements s/AC_/AC_LIB/ and s/lt_cv/acl_cv/ to avoid collision dnl with libtool.m4. dnl From libtool-1.4. Sets the variable with_gnu_ld to yes or no. AC_DEFUN([AC_LIB_PROG_LD_GNU], [AC_CACHE_CHECK([if the linker ($LD) is GNU ld], acl_cv_prog_gnu_ld, [# I'd rather use --version here, but apparently some GNU ld's only accept -v. case `$LD -v 2>&1 conf$$.sh echo "exit 0" >>conf$$.sh chmod +x conf$$.sh if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then PATH_SEPARATOR=';' else PATH_SEPARATOR=: fi rm -f conf$$.sh fi ac_prog=ld if test "$GCC" = yes; then # Check if gcc -print-prog-name=ld gives a path. AC_MSG_CHECKING([for ld used by GCC]) case $host in *-*-mingw*) # gcc leaves a trailing carriage return which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case $ac_prog in # Accept absolute paths. [[\\/]* | [A-Za-z]:[\\/]*)] [re_direlt='/[^/][^/]*/\.\./'] # Canonicalize the path of ld ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'` while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"` done test -z "$LD" && LD="$ac_prog" ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test "$with_gnu_ld" = yes; then AC_MSG_CHECKING([for GNU ld]) else AC_MSG_CHECKING([for non-GNU ld]) fi AC_CACHE_VAL(acl_cv_path_LD, [if test -z "$LD"; then IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}" for ac_dir in $PATH; do test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then acl_cv_path_LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some GNU ld's only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$acl_cv_path_LD" -v 2>&1 < /dev/null` in *GNU* | *'with BFD'*) test "$with_gnu_ld" != no && break ;; *) test "$with_gnu_ld" != yes && break ;; esac fi done IFS="$ac_save_ifs" else acl_cv_path_LD="$LD" # Let the user override the test with a path. fi]) LD="$acl_cv_path_LD" if test -n "$LD"; then AC_MSG_RESULT($LD) else AC_MSG_RESULT(no) fi test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH]) AC_LIB_PROG_LD_GNU ]) partclone-0.2.86/m4/lib-link.m4000066400000000000000000000642441262102574200160740ustar00rootroot00000000000000# lib-link.m4 serial 9 (gettext-0.16) dnl Copyright (C) 2001-2006 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Bruno Haible. AC_PREREQ(2.50) dnl AC_LIB_LINKFLAGS(name [, dependencies]) searches for libname and dnl the libraries corresponding to explicit and implicit dependencies. dnl Sets and AC_SUBSTs the LIB${NAME} and LTLIB${NAME} variables and dnl augments the CPPFLAGS variable. AC_DEFUN([AC_LIB_LINKFLAGS], [ AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) AC_REQUIRE([AC_LIB_RPATH]) define([Name],[translit([$1],[./-], [___])]) define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-], [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) AC_CACHE_CHECK([how to link with lib[]$1], [ac_cv_lib[]Name[]_libs], [ AC_LIB_LINKFLAGS_BODY([$1], [$2]) ac_cv_lib[]Name[]_libs="$LIB[]NAME" ac_cv_lib[]Name[]_ltlibs="$LTLIB[]NAME" ac_cv_lib[]Name[]_cppflags="$INC[]NAME" ]) LIB[]NAME="$ac_cv_lib[]Name[]_libs" LTLIB[]NAME="$ac_cv_lib[]Name[]_ltlibs" INC[]NAME="$ac_cv_lib[]Name[]_cppflags" AC_LIB_APPENDTOVAR([CPPFLAGS], [$INC]NAME) AC_SUBST([LIB]NAME) AC_SUBST([LTLIB]NAME) dnl Also set HAVE_LIB[]NAME so that AC_LIB_HAVE_LINKFLAGS can reuse the dnl results of this search when this library appears as a dependency. HAVE_LIB[]NAME=yes undefine([Name]) undefine([NAME]) ]) dnl AC_LIB_HAVE_LINKFLAGS(name, dependencies, includes, testcode) dnl searches for libname and the libraries corresponding to explicit and dnl implicit dependencies, together with the specified include files and dnl the ability to compile and link the specified testcode. If found, it dnl sets and AC_SUBSTs HAVE_LIB${NAME}=yes and the LIB${NAME} and dnl LTLIB${NAME} variables and augments the CPPFLAGS variable, and dnl #defines HAVE_LIB${NAME} to 1. Otherwise, it sets and AC_SUBSTs dnl HAVE_LIB${NAME}=no and LIB${NAME} and LTLIB${NAME} to empty. AC_DEFUN([AC_LIB_HAVE_LINKFLAGS], [ AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) AC_REQUIRE([AC_LIB_RPATH]) define([Name],[translit([$1],[./-], [___])]) define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-], [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) dnl Search for lib[]Name and define LIB[]NAME, LTLIB[]NAME and INC[]NAME dnl accordingly. AC_LIB_LINKFLAGS_BODY([$1], [$2]) dnl Add $INC[]NAME to CPPFLAGS before performing the following checks, dnl because if the user has installed lib[]Name and not disabled its use dnl via --without-lib[]Name-prefix, he wants to use it. ac_save_CPPFLAGS="$CPPFLAGS" AC_LIB_APPENDTOVAR([CPPFLAGS], [$INC]NAME) AC_CACHE_CHECK([for lib[]$1], [ac_cv_lib[]Name], [ ac_save_LIBS="$LIBS" LIBS="$LIBS $LIB[]NAME" AC_TRY_LINK([$3], [$4], [ac_cv_lib[]Name=yes], [ac_cv_lib[]Name=no]) LIBS="$ac_save_LIBS" ]) if test "$ac_cv_lib[]Name" = yes; then HAVE_LIB[]NAME=yes AC_DEFINE([HAVE_LIB]NAME, 1, [Define if you have the $1 library.]) AC_MSG_CHECKING([how to link with lib[]$1]) AC_MSG_RESULT([$LIB[]NAME]) else HAVE_LIB[]NAME=no dnl If $LIB[]NAME didn't lead to a usable library, we don't need dnl $INC[]NAME either. CPPFLAGS="$ac_save_CPPFLAGS" LIB[]NAME= LTLIB[]NAME= fi AC_SUBST([HAVE_LIB]NAME) AC_SUBST([LIB]NAME) AC_SUBST([LTLIB]NAME) undefine([Name]) undefine([NAME]) ]) dnl Determine the platform dependent parameters needed to use rpath: dnl libext, shlibext, hardcode_libdir_flag_spec, hardcode_libdir_separator, dnl hardcode_direct, hardcode_minus_L. AC_DEFUN([AC_LIB_RPATH], [ dnl Tell automake >= 1.10 to complain if config.rpath is missing. m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([config.rpath])]) AC_REQUIRE([AC_PROG_CC]) dnl we use $CC, $GCC, $LDFLAGS AC_REQUIRE([AC_LIB_PROG_LD]) dnl we use $LD, $with_gnu_ld AC_REQUIRE([AC_CANONICAL_HOST]) dnl we use $host AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT]) dnl we use $ac_aux_dir AC_CACHE_CHECK([for shared library run path origin], acl_cv_rpath, [ CC="$CC" GCC="$GCC" LDFLAGS="$LDFLAGS" LD="$LD" with_gnu_ld="$with_gnu_ld" \ ${CONFIG_SHELL-/bin/sh} "$ac_aux_dir/config.rpath" "$host" > conftest.sh . ./conftest.sh rm -f ./conftest.sh acl_cv_rpath=done ]) wl="$acl_cv_wl" libext="$acl_cv_libext" shlibext="$acl_cv_shlibext" hardcode_libdir_flag_spec="$acl_cv_hardcode_libdir_flag_spec" hardcode_libdir_separator="$acl_cv_hardcode_libdir_separator" hardcode_direct="$acl_cv_hardcode_direct" hardcode_minus_L="$acl_cv_hardcode_minus_L" dnl Determine whether the user wants rpath handling at all. AC_ARG_ENABLE(rpath, [ --disable-rpath do not hardcode runtime library paths], :, enable_rpath=yes) ]) dnl AC_LIB_LINKFLAGS_BODY(name [, dependencies]) searches for libname and dnl the libraries corresponding to explicit and implicit dependencies. dnl Sets the LIB${NAME}, LTLIB${NAME} and INC${NAME} variables. AC_DEFUN([AC_LIB_LINKFLAGS_BODY], [ AC_REQUIRE([AC_LIB_PREPARE_MULTILIB]) define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-], [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) dnl By default, look in $includedir and $libdir. use_additional=yes AC_LIB_WITH_FINAL_PREFIX([ eval additional_includedir=\"$includedir\" eval additional_libdir=\"$libdir\" ]) AC_LIB_ARG_WITH([lib$1-prefix], [ --with-lib$1-prefix[=DIR] search for lib$1 in DIR/include and DIR/lib --without-lib$1-prefix don't search for lib$1 in includedir and libdir], [ if test "X$withval" = "Xno"; then use_additional=no else if test "X$withval" = "X"; then AC_LIB_WITH_FINAL_PREFIX([ eval additional_includedir=\"$includedir\" eval additional_libdir=\"$libdir\" ]) else additional_includedir="$withval/include" additional_libdir="$withval/$acl_libdirstem" fi fi ]) dnl Search the library and its dependencies in $additional_libdir and dnl $LDFLAGS. Using breadth-first-seach. LIB[]NAME= LTLIB[]NAME= INC[]NAME= rpathdirs= ltrpathdirs= names_already_handled= names_next_round='$1 $2' while test -n "$names_next_round"; do names_this_round="$names_next_round" names_next_round= for name in $names_this_round; do already_handled= for n in $names_already_handled; do if test "$n" = "$name"; then already_handled=yes break fi done if test -z "$already_handled"; then names_already_handled="$names_already_handled $name" dnl See if it was already located by an earlier AC_LIB_LINKFLAGS dnl or AC_LIB_HAVE_LINKFLAGS call. uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./-|ABCDEFGHIJKLMNOPQRSTUVWXYZ___|'` eval value=\"\$HAVE_LIB$uppername\" if test -n "$value"; then if test "$value" = yes; then eval value=\"\$LIB$uppername\" test -z "$value" || LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$value" eval value=\"\$LTLIB$uppername\" test -z "$value" || LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$value" else dnl An earlier call to AC_LIB_HAVE_LINKFLAGS has determined dnl that this library doesn't exist. So just drop it. : fi else dnl Search the library lib$name in $additional_libdir and $LDFLAGS dnl and the already constructed $LIBNAME/$LTLIBNAME. found_dir= found_la= found_so= found_a= if test $use_additional = yes; then if test -n "$shlibext" \ && { test -f "$additional_libdir/lib$name.$shlibext" \ || { test "$shlibext" = dll \ && test -f "$additional_libdir/lib$name.dll.a"; }; }; then found_dir="$additional_libdir" if test -f "$additional_libdir/lib$name.$shlibext"; then found_so="$additional_libdir/lib$name.$shlibext" else found_so="$additional_libdir/lib$name.dll.a" fi if test -f "$additional_libdir/lib$name.la"; then found_la="$additional_libdir/lib$name.la" fi else if test -f "$additional_libdir/lib$name.$libext"; then found_dir="$additional_libdir" found_a="$additional_libdir/lib$name.$libext" if test -f "$additional_libdir/lib$name.la"; then found_la="$additional_libdir/lib$name.la" fi fi fi fi if test "X$found_dir" = "X"; then for x in $LDFLAGS $LTLIB[]NAME; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) case "$x" in -L*) dir=`echo "X$x" | sed -e 's/^X-L//'` if test -n "$shlibext" \ && { test -f "$dir/lib$name.$shlibext" \ || { test "$shlibext" = dll \ && test -f "$dir/lib$name.dll.a"; }; }; then found_dir="$dir" if test -f "$dir/lib$name.$shlibext"; then found_so="$dir/lib$name.$shlibext" else found_so="$dir/lib$name.dll.a" fi if test -f "$dir/lib$name.la"; then found_la="$dir/lib$name.la" fi else if test -f "$dir/lib$name.$libext"; then found_dir="$dir" found_a="$dir/lib$name.$libext" if test -f "$dir/lib$name.la"; then found_la="$dir/lib$name.la" fi fi fi ;; esac if test "X$found_dir" != "X"; then break fi done fi if test "X$found_dir" != "X"; then dnl Found the library. LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$found_dir -l$name" if test "X$found_so" != "X"; then dnl Linking with a shared library. We attempt to hardcode its dnl directory into the executable's runpath, unless it's the dnl standard /usr/lib. if test "$enable_rpath" = no || test "X$found_dir" = "X/usr/$acl_libdirstem"; then dnl No hardcoding is needed. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" else dnl Use an explicit option to hardcode DIR into the resulting dnl binary. dnl Potentially add DIR to ltrpathdirs. dnl The ltrpathdirs will be appended to $LTLIBNAME at the end. haveit= for x in $ltrpathdirs; do if test "X$x" = "X$found_dir"; then haveit=yes break fi done if test -z "$haveit"; then ltrpathdirs="$ltrpathdirs $found_dir" fi dnl The hardcoding into $LIBNAME is system dependent. if test "$hardcode_direct" = yes; then dnl Using DIR/libNAME.so during linking hardcodes DIR into the dnl resulting binary. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" else if test -n "$hardcode_libdir_flag_spec" && test "$hardcode_minus_L" = no; then dnl Use an explicit option to hardcode DIR into the resulting dnl binary. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" dnl Potentially add DIR to rpathdirs. dnl The rpathdirs will be appended to $LIBNAME at the end. haveit= for x in $rpathdirs; do if test "X$x" = "X$found_dir"; then haveit=yes break fi done if test -z "$haveit"; then rpathdirs="$rpathdirs $found_dir" fi else dnl Rely on "-L$found_dir". dnl But don't add it if it's already contained in the LDFLAGS dnl or the already constructed $LIBNAME haveit= for x in $LDFLAGS $LIB[]NAME; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X-L$found_dir"; then haveit=yes break fi done if test -z "$haveit"; then LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir" fi if test "$hardcode_minus_L" != no; then dnl FIXME: Not sure whether we should use dnl "-L$found_dir -l$name" or "-L$found_dir $found_so" dnl here. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" else dnl We cannot use $hardcode_runpath_var and LD_RUN_PATH dnl here, because this doesn't fit in flags passed to the dnl compiler. So give up. No hardcoding. This affects only dnl very old systems. dnl FIXME: Not sure whether we should use dnl "-L$found_dir -l$name" or "-L$found_dir $found_so" dnl here. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name" fi fi fi fi else if test "X$found_a" != "X"; then dnl Linking with a static library. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_a" else dnl We shouldn't come here, but anyway it's good to have a dnl fallback. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir -l$name" fi fi dnl Assume the include files are nearby. additional_includedir= case "$found_dir" in */$acl_libdirstem | */$acl_libdirstem/) basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem/"'*$,,'` additional_includedir="$basedir/include" ;; esac if test "X$additional_includedir" != "X"; then dnl Potentially add $additional_includedir to $INCNAME. dnl But don't add it dnl 1. if it's the standard /usr/include, dnl 2. if it's /usr/local/include and we are using GCC on Linux, dnl 3. if it's already present in $CPPFLAGS or the already dnl constructed $INCNAME, dnl 4. if it doesn't exist as a directory. if test "X$additional_includedir" != "X/usr/include"; then haveit= if test "X$additional_includedir" = "X/usr/local/include"; then if test -n "$GCC"; then case $host_os in linux* | gnu* | k*bsd*-gnu) haveit=yes;; esac fi fi if test -z "$haveit"; then for x in $CPPFLAGS $INC[]NAME; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X-I$additional_includedir"; then haveit=yes break fi done if test -z "$haveit"; then if test -d "$additional_includedir"; then dnl Really add $additional_includedir to $INCNAME. INC[]NAME="${INC[]NAME}${INC[]NAME:+ }-I$additional_includedir" fi fi fi fi fi dnl Look for dependencies. if test -n "$found_la"; then dnl Read the .la file. It defines the variables dnl dlname, library_names, old_library, dependency_libs, current, dnl age, revision, installed, dlopen, dlpreopen, libdir. save_libdir="$libdir" case "$found_la" in */* | *\\*) . "$found_la" ;; *) . "./$found_la" ;; esac libdir="$save_libdir" dnl We use only dependency_libs. for dep in $dependency_libs; do case "$dep" in -L*) additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'` dnl Potentially add $additional_libdir to $LIBNAME and $LTLIBNAME. dnl But don't add it dnl 1. if it's the standard /usr/lib, dnl 2. if it's /usr/local/lib and we are using GCC on Linux, dnl 3. if it's already present in $LDFLAGS or the already dnl constructed $LIBNAME, dnl 4. if it doesn't exist as a directory. if test "X$additional_libdir" != "X/usr/$acl_libdirstem"; then haveit= if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem"; then if test -n "$GCC"; then case $host_os in linux* | gnu* | k*bsd*-gnu) haveit=yes;; esac fi fi if test -z "$haveit"; then haveit= for x in $LDFLAGS $LIB[]NAME; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X-L$additional_libdir"; then haveit=yes break fi done if test -z "$haveit"; then if test -d "$additional_libdir"; then dnl Really add $additional_libdir to $LIBNAME. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$additional_libdir" fi fi haveit= for x in $LDFLAGS $LTLIB[]NAME; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X-L$additional_libdir"; then haveit=yes break fi done if test -z "$haveit"; then if test -d "$additional_libdir"; then dnl Really add $additional_libdir to $LTLIBNAME. LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$additional_libdir" fi fi fi fi ;; -R*) dir=`echo "X$dep" | sed -e 's/^X-R//'` if test "$enable_rpath" != no; then dnl Potentially add DIR to rpathdirs. dnl The rpathdirs will be appended to $LIBNAME at the end. haveit= for x in $rpathdirs; do if test "X$x" = "X$dir"; then haveit=yes break fi done if test -z "$haveit"; then rpathdirs="$rpathdirs $dir" fi dnl Potentially add DIR to ltrpathdirs. dnl The ltrpathdirs will be appended to $LTLIBNAME at the end. haveit= for x in $ltrpathdirs; do if test "X$x" = "X$dir"; then haveit=yes break fi done if test -z "$haveit"; then ltrpathdirs="$ltrpathdirs $dir" fi fi ;; -l*) dnl Handle this in the next round. names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'` ;; *.la) dnl Handle this in the next round. Throw away the .la's dnl directory; it is already contained in a preceding -L dnl option. names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'` ;; *) dnl Most likely an immediate library name. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$dep" LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$dep" ;; esac done fi else dnl Didn't find the library; assume it is in the system directories dnl known to the linker and runtime loader. (All the system dnl directories known to the linker should also be known to the dnl runtime loader, otherwise the system is severely misconfigured.) LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name" LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-l$name" fi fi fi done done if test "X$rpathdirs" != "X"; then if test -n "$hardcode_libdir_separator"; then dnl Weird platform: only the last -rpath option counts, the user must dnl pass all path elements in one option. We can arrange that for a dnl single library, but not when more than one $LIBNAMEs are used. alldirs= for found_dir in $rpathdirs; do alldirs="${alldirs}${alldirs:+$hardcode_libdir_separator}$found_dir" done dnl Note: hardcode_libdir_flag_spec uses $libdir and $wl. acl_save_libdir="$libdir" libdir="$alldirs" eval flag=\"$hardcode_libdir_flag_spec\" libdir="$acl_save_libdir" LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag" else dnl The -rpath options are cumulative. for found_dir in $rpathdirs; do acl_save_libdir="$libdir" libdir="$found_dir" eval flag=\"$hardcode_libdir_flag_spec\" libdir="$acl_save_libdir" LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag" done fi fi if test "X$ltrpathdirs" != "X"; then dnl When using libtool, the option that works for both libraries and dnl executables is -R. The -R options are cumulative. for found_dir in $ltrpathdirs; do LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-R$found_dir" done fi ]) dnl AC_LIB_APPENDTOVAR(VAR, CONTENTS) appends the elements of CONTENTS to VAR, dnl unless already present in VAR. dnl Works only for CPPFLAGS, not for LIB* variables because that sometimes dnl contains two or three consecutive elements that belong together. AC_DEFUN([AC_LIB_APPENDTOVAR], [ for element in [$2]; do haveit= for x in $[$1]; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X$element"; then haveit=yes break fi done if test -z "$haveit"; then [$1]="${[$1]}${[$1]:+ }$element" fi done ]) dnl For those cases where a variable contains several -L and -l options dnl referring to unknown libraries and directories, this macro determines the dnl necessary additional linker options for the runtime path. dnl AC_LIB_LINKFLAGS_FROM_LIBS([LDADDVAR], [LIBSVALUE], [USE-LIBTOOL]) dnl sets LDADDVAR to linker options needed together with LIBSVALUE. dnl If USE-LIBTOOL evaluates to non-empty, linking with libtool is assumed, dnl otherwise linking without libtool is assumed. AC_DEFUN([AC_LIB_LINKFLAGS_FROM_LIBS], [ AC_REQUIRE([AC_LIB_RPATH]) AC_REQUIRE([AC_LIB_PREPARE_MULTILIB]) $1= if test "$enable_rpath" != no; then if test -n "$hardcode_libdir_flag_spec" && test "$hardcode_minus_L" = no; then dnl Use an explicit option to hardcode directories into the resulting dnl binary. rpathdirs= next= for opt in $2; do if test -n "$next"; then dir="$next" dnl No need to hardcode the standard /usr/lib. if test "X$dir" != "X/usr/$acl_libdirstem"; then rpathdirs="$rpathdirs $dir" fi next= else case $opt in -L) next=yes ;; -L*) dir=`echo "X$opt" | sed -e 's,^X-L,,'` dnl No need to hardcode the standard /usr/lib. if test "X$dir" != "X/usr/$acl_libdirstem"; then rpathdirs="$rpathdirs $dir" fi next= ;; *) next= ;; esac fi done if test "X$rpathdirs" != "X"; then if test -n ""$3""; then dnl libtool is used for linking. Use -R options. for dir in $rpathdirs; do $1="${$1}${$1:+ }-R$dir" done else dnl The linker is used for linking directly. if test -n "$hardcode_libdir_separator"; then dnl Weird platform: only the last -rpath option counts, the user dnl must pass all path elements in one option. alldirs= for dir in $rpathdirs; do alldirs="${alldirs}${alldirs:+$hardcode_libdir_separator}$dir" done acl_save_libdir="$libdir" libdir="$alldirs" eval flag=\"$hardcode_libdir_flag_spec\" libdir="$acl_save_libdir" $1="$flag" else dnl The -rpath options are cumulative. for dir in $rpathdirs; do acl_save_libdir="$libdir" libdir="$dir" eval flag=\"$hardcode_libdir_flag_spec\" libdir="$acl_save_libdir" $1="${$1}${$1:+ }$flag" done fi fi fi fi fi AC_SUBST([$1]) ]) partclone-0.2.86/m4/lib-prefix.m4000066400000000000000000000150361262102574200164270ustar00rootroot00000000000000# lib-prefix.m4 serial 5 (gettext-0.15) dnl Copyright (C) 2001-2005 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Bruno Haible. dnl AC_LIB_ARG_WITH is synonymous to AC_ARG_WITH in autoconf-2.13, and dnl similar to AC_ARG_WITH in autoconf 2.52...2.57 except that is doesn't dnl require excessive bracketing. ifdef([AC_HELP_STRING], [AC_DEFUN([AC_LIB_ARG_WITH], [AC_ARG_WITH([$1],[[$2]],[$3],[$4])])], [AC_DEFUN([AC_][LIB_ARG_WITH], [AC_ARG_WITH([$1],[$2],[$3],[$4])])]) dnl AC_LIB_PREFIX adds to the CPPFLAGS and LDFLAGS the flags that are needed dnl to access previously installed libraries. The basic assumption is that dnl a user will want packages to use other packages he previously installed dnl with the same --prefix option. dnl This macro is not needed if only AC_LIB_LINKFLAGS is used to locate dnl libraries, but is otherwise very convenient. AC_DEFUN([AC_LIB_PREFIX], [ AC_BEFORE([$0], [AC_LIB_LINKFLAGS]) AC_REQUIRE([AC_PROG_CC]) AC_REQUIRE([AC_CANONICAL_HOST]) AC_REQUIRE([AC_LIB_PREPARE_MULTILIB]) AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) dnl By default, look in $includedir and $libdir. use_additional=yes AC_LIB_WITH_FINAL_PREFIX([ eval additional_includedir=\"$includedir\" eval additional_libdir=\"$libdir\" ]) AC_LIB_ARG_WITH([lib-prefix], [ --with-lib-prefix[=DIR] search for libraries in DIR/include and DIR/lib --without-lib-prefix don't search for libraries in includedir and libdir], [ if test "X$withval" = "Xno"; then use_additional=no else if test "X$withval" = "X"; then AC_LIB_WITH_FINAL_PREFIX([ eval additional_includedir=\"$includedir\" eval additional_libdir=\"$libdir\" ]) else additional_includedir="$withval/include" additional_libdir="$withval/$acl_libdirstem" fi fi ]) if test $use_additional = yes; then dnl Potentially add $additional_includedir to $CPPFLAGS. dnl But don't add it dnl 1. if it's the standard /usr/include, dnl 2. if it's already present in $CPPFLAGS, dnl 3. if it's /usr/local/include and we are using GCC on Linux, dnl 4. if it doesn't exist as a directory. if test "X$additional_includedir" != "X/usr/include"; then haveit= for x in $CPPFLAGS; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X-I$additional_includedir"; then haveit=yes break fi done if test -z "$haveit"; then if test "X$additional_includedir" = "X/usr/local/include"; then if test -n "$GCC"; then case $host_os in linux* | gnu* | k*bsd*-gnu) haveit=yes;; esac fi fi if test -z "$haveit"; then if test -d "$additional_includedir"; then dnl Really add $additional_includedir to $CPPFLAGS. CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }-I$additional_includedir" fi fi fi fi dnl Potentially add $additional_libdir to $LDFLAGS. dnl But don't add it dnl 1. if it's the standard /usr/lib, dnl 2. if it's already present in $LDFLAGS, dnl 3. if it's /usr/local/lib and we are using GCC on Linux, dnl 4. if it doesn't exist as a directory. if test "X$additional_libdir" != "X/usr/$acl_libdirstem"; then haveit= for x in $LDFLAGS; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X-L$additional_libdir"; then haveit=yes break fi done if test -z "$haveit"; then if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem"; then if test -n "$GCC"; then case $host_os in linux*) haveit=yes;; esac fi fi if test -z "$haveit"; then if test -d "$additional_libdir"; then dnl Really add $additional_libdir to $LDFLAGS. LDFLAGS="${LDFLAGS}${LDFLAGS:+ }-L$additional_libdir" fi fi fi fi fi ]) dnl AC_LIB_PREPARE_PREFIX creates variables acl_final_prefix, dnl acl_final_exec_prefix, containing the values to which $prefix and dnl $exec_prefix will expand at the end of the configure script. AC_DEFUN([AC_LIB_PREPARE_PREFIX], [ dnl Unfortunately, prefix and exec_prefix get only finally determined dnl at the end of configure. if test "X$prefix" = "XNONE"; then acl_final_prefix="$ac_default_prefix" else acl_final_prefix="$prefix" fi if test "X$exec_prefix" = "XNONE"; then acl_final_exec_prefix='${prefix}' else acl_final_exec_prefix="$exec_prefix" fi acl_save_prefix="$prefix" prefix="$acl_final_prefix" eval acl_final_exec_prefix=\"$acl_final_exec_prefix\" prefix="$acl_save_prefix" ]) dnl AC_LIB_WITH_FINAL_PREFIX([statement]) evaluates statement, with the dnl variables prefix and exec_prefix bound to the values they will have dnl at the end of the configure script. AC_DEFUN([AC_LIB_WITH_FINAL_PREFIX], [ acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" $1 exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" ]) dnl AC_LIB_PREPARE_MULTILIB creates a variable acl_libdirstem, containing dnl the basename of the libdir, either "lib" or "lib64". AC_DEFUN([AC_LIB_PREPARE_MULTILIB], [ dnl There is no formal standard regarding lib and lib64. The current dnl practice is that on a system supporting 32-bit and 64-bit instruction dnl sets or ABIs, 64-bit libraries go under $prefix/lib64 and 32-bit dnl libraries go under $prefix/lib. We determine the compiler's default dnl mode by looking at the compiler's library search path. If at least dnl of its elements ends in /lib64 or points to a directory whose absolute dnl pathname ends in /lib64, we assume a 64-bit ABI. Otherwise we use the dnl default, namely "lib". acl_libdirstem=lib searchpath=`(LC_ALL=C $CC -print-search-dirs) 2>/dev/null | sed -n -e 's,^libraries: ,,p' | sed -e 's,^=,,'` if test -n "$searchpath"; then acl_save_IFS="${IFS= }"; IFS=":" for searchdir in $searchpath; do if test -d "$searchdir"; then case "$searchdir" in */lib64/ | */lib64 ) acl_libdirstem=lib64 ;; *) searchdir=`cd "$searchdir" && pwd` case "$searchdir" in */lib64 ) acl_libdirstem=lib64 ;; esac ;; esac fi done IFS="$acl_save_IFS" fi ]) partclone-0.2.86/m4/nls.m4000066400000000000000000000022661262102574200151630ustar00rootroot00000000000000# nls.m4 serial 3 (gettext-0.15) dnl Copyright (C) 1995-2003, 2005-2006 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl dnl This file can can be used in projects which are not available under dnl the GNU General Public License or the GNU Library General Public dnl License but which still want to provide support for the GNU gettext dnl functionality. dnl Please note that the actual code of the GNU gettext library is covered dnl by the GNU Library General Public License, and the rest of the GNU dnl gettext package package is covered by the GNU General Public License. dnl They are *not* in the public domain. dnl Authors: dnl Ulrich Drepper , 1995-2000. dnl Bruno Haible , 2000-2003. AC_PREREQ(2.50) AC_DEFUN([AM_NLS], [ AC_MSG_CHECKING([whether NLS is requested]) dnl Default is enabled NLS AC_ARG_ENABLE(nls, [ --disable-nls do not use Native Language Support], USE_NLS=$enableval, USE_NLS=yes) AC_MSG_RESULT($USE_NLS) AC_SUBST(USE_NLS) ]) partclone-0.2.86/m4/po.m4000066400000000000000000000433671262102574200150140ustar00rootroot00000000000000# po.m4 serial 13 (gettext-0.15) dnl Copyright (C) 1995-2006 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl dnl This file can can be used in projects which are not available under dnl the GNU General Public License or the GNU Library General Public dnl License but which still want to provide support for the GNU gettext dnl functionality. dnl Please note that the actual code of the GNU gettext library is covered dnl by the GNU Library General Public License, and the rest of the GNU dnl gettext package package is covered by the GNU General Public License. dnl They are *not* in the public domain. dnl Authors: dnl Ulrich Drepper , 1995-2000. dnl Bruno Haible , 2000-2003. AC_PREREQ(2.50) dnl Checks for all prerequisites of the po subdirectory. AC_DEFUN([AM_PO_SUBDIRS], [ AC_REQUIRE([AC_PROG_MAKE_SET])dnl AC_REQUIRE([AC_PROG_INSTALL])dnl AC_REQUIRE([AM_PROG_MKDIR_P])dnl defined by automake AC_REQUIRE([AM_NLS])dnl dnl Perform the following tests also if --disable-nls has been given, dnl because they are needed for "make dist" to work. dnl Search for GNU msgfmt in the PATH. dnl The first test excludes Solaris msgfmt and early GNU msgfmt versions. dnl The second test excludes FreeBSD msgfmt. AM_PATH_PROG_WITH_TEST(MSGFMT, msgfmt, [$ac_dir/$ac_word --statistics /dev/null >&]AS_MESSAGE_LOG_FD[ 2>&1 && (if $ac_dir/$ac_word --statistics /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi)], :) AC_PATH_PROG(GMSGFMT, gmsgfmt, $MSGFMT) dnl Test whether it is GNU msgfmt >= 0.15. changequote(,)dnl case `$MSGFMT --version | sed 1q | sed -e 's,^[^0-9]*,,'` in '' | 0.[0-9] | 0.[0-9].* | 0.1[0-4] | 0.1[0-4].*) MSGFMT_015=: ;; *) MSGFMT_015=$MSGFMT ;; esac changequote([,])dnl AC_SUBST([MSGFMT_015]) changequote(,)dnl case `$GMSGFMT --version | sed 1q | sed -e 's,^[^0-9]*,,'` in '' | 0.[0-9] | 0.[0-9].* | 0.1[0-4] | 0.1[0-4].*) GMSGFMT_015=: ;; *) GMSGFMT_015=$GMSGFMT ;; esac changequote([,])dnl AC_SUBST([GMSGFMT_015]) dnl Search for GNU xgettext 0.12 or newer in the PATH. dnl The first test excludes Solaris xgettext and early GNU xgettext versions. dnl The second test excludes FreeBSD xgettext. AM_PATH_PROG_WITH_TEST(XGETTEXT, xgettext, [$ac_dir/$ac_word --omit-header --copyright-holder= --msgid-bugs-address= /dev/null >&]AS_MESSAGE_LOG_FD[ 2>&1 && (if $ac_dir/$ac_word --omit-header --copyright-holder= --msgid-bugs-address= /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi)], :) dnl Remove leftover from FreeBSD xgettext call. rm -f messages.po dnl Test whether it is GNU xgettext >= 0.15. changequote(,)dnl case `$XGETTEXT --version | sed 1q | sed -e 's,^[^0-9]*,,'` in '' | 0.[0-9] | 0.[0-9].* | 0.1[0-4] | 0.1[0-4].*) XGETTEXT_015=: ;; *) XGETTEXT_015=$XGETTEXT ;; esac changequote([,])dnl AC_SUBST([XGETTEXT_015]) dnl Search for GNU msgmerge 0.11 or newer in the PATH. AM_PATH_PROG_WITH_TEST(MSGMERGE, msgmerge, [$ac_dir/$ac_word --update -q /dev/null /dev/null >&]AS_MESSAGE_LOG_FD[ 2>&1], :) dnl Installation directories. dnl Autoconf >= 2.60 defines localedir. For older versions of autoconf, we dnl have to define it here, so that it can be used in po/Makefile. test -n "$localedir" || localedir='${datadir}/locale' AC_SUBST([localedir]) AC_CONFIG_COMMANDS([po-directories], [[ for ac_file in $CONFIG_FILES; do # Support "outfile[:infile[:infile...]]" case "$ac_file" in *:*) ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; esac # PO directories have a Makefile.in generated from Makefile.in.in. case "$ac_file" in */Makefile.in) # Adjust a relative srcdir. ac_dir=`echo "$ac_file"|sed 's%/[^/][^/]*$%%'` ac_dir_suffix="/`echo "$ac_dir"|sed 's%^\./%%'`" ac_dots=`echo "$ac_dir_suffix"|sed 's%/[^/]*%../%g'` # In autoconf-2.13 it is called $ac_given_srcdir. # In autoconf-2.50 it is called $srcdir. test -n "$ac_given_srcdir" || ac_given_srcdir="$srcdir" case "$ac_given_srcdir" in .) top_srcdir=`echo $ac_dots|sed 's%/$%%'` ;; /*) top_srcdir="$ac_given_srcdir" ;; *) top_srcdir="$ac_dots$ac_given_srcdir" ;; esac # Treat a directory as a PO directory if and only if it has a # POTFILES.in file. This allows packages to have multiple PO # directories under different names or in different locations. if test -f "$ac_given_srcdir/$ac_dir/POTFILES.in"; then rm -f "$ac_dir/POTFILES" test -n "$as_me" && echo "$as_me: creating $ac_dir/POTFILES" || echo "creating $ac_dir/POTFILES" cat "$ac_given_srcdir/$ac_dir/POTFILES.in" | sed -e "/^#/d" -e "/^[ ]*\$/d" -e "s,.*, $top_srcdir/& \\\\," | sed -e "\$s/\(.*\) \\\\/\1/" > "$ac_dir/POTFILES" POMAKEFILEDEPS="POTFILES.in" # ALL_LINGUAS, POFILES, UPDATEPOFILES, DUMMYPOFILES, GMOFILES depend # on $ac_dir but don't depend on user-specified configuration # parameters. if test -f "$ac_given_srcdir/$ac_dir/LINGUAS"; then # The LINGUAS file contains the set of available languages. if test -n "$OBSOLETE_ALL_LINGUAS"; then test -n "$as_me" && echo "$as_me: setting ALL_LINGUAS in configure.in is obsolete" || echo "setting ALL_LINGUAS in configure.in is obsolete" fi ALL_LINGUAS_=`sed -e "/^#/d" -e "s/#.*//" "$ac_given_srcdir/$ac_dir/LINGUAS"` # Hide the ALL_LINGUAS assigment from automake < 1.5. eval 'ALL_LINGUAS''=$ALL_LINGUAS_' POMAKEFILEDEPS="$POMAKEFILEDEPS LINGUAS" else # The set of available languages was given in configure.in. # Hide the ALL_LINGUAS assigment from automake < 1.5. eval 'ALL_LINGUAS''=$OBSOLETE_ALL_LINGUAS' fi # Compute POFILES # as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).po) # Compute UPDATEPOFILES # as $(foreach lang, $(ALL_LINGUAS), $(lang).po-update) # Compute DUMMYPOFILES # as $(foreach lang, $(ALL_LINGUAS), $(lang).nop) # Compute GMOFILES # as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).gmo) case "$ac_given_srcdir" in .) srcdirpre= ;; *) srcdirpre='$(srcdir)/' ;; esac POFILES= UPDATEPOFILES= DUMMYPOFILES= GMOFILES= for lang in $ALL_LINGUAS; do POFILES="$POFILES $srcdirpre$lang.po" UPDATEPOFILES="$UPDATEPOFILES $lang.po-update" DUMMYPOFILES="$DUMMYPOFILES $lang.nop" GMOFILES="$GMOFILES $srcdirpre$lang.gmo" done # CATALOGS depends on both $ac_dir and the user's LINGUAS # environment variable. INST_LINGUAS= if test -n "$ALL_LINGUAS"; then for presentlang in $ALL_LINGUAS; do useit=no if test "%UNSET%" != "$LINGUAS"; then desiredlanguages="$LINGUAS" else desiredlanguages="$ALL_LINGUAS" fi for desiredlang in $desiredlanguages; do # Use the presentlang catalog if desiredlang is # a. equal to presentlang, or # b. a variant of presentlang (because in this case, # presentlang can be used as a fallback for messages # which are not translated in the desiredlang catalog). case "$desiredlang" in "$presentlang"*) useit=yes;; esac done if test $useit = yes; then INST_LINGUAS="$INST_LINGUAS $presentlang" fi done fi CATALOGS= if test -n "$INST_LINGUAS"; then for lang in $INST_LINGUAS; do CATALOGS="$CATALOGS $lang.gmo" done fi test -n "$as_me" && echo "$as_me: creating $ac_dir/Makefile" || echo "creating $ac_dir/Makefile" sed -e "/^POTFILES =/r $ac_dir/POTFILES" -e "/^# Makevars/r $ac_given_srcdir/$ac_dir/Makevars" -e "s|@POFILES@|$POFILES|g" -e "s|@UPDATEPOFILES@|$UPDATEPOFILES|g" -e "s|@DUMMYPOFILES@|$DUMMYPOFILES|g" -e "s|@GMOFILES@|$GMOFILES|g" -e "s|@CATALOGS@|$CATALOGS|g" -e "s|@POMAKEFILEDEPS@|$POMAKEFILEDEPS|g" "$ac_dir/Makefile.in" > "$ac_dir/Makefile" for f in "$ac_given_srcdir/$ac_dir"/Rules-*; do if test -f "$f"; then case "$f" in *.orig | *.bak | *~) ;; *) cat "$f" >> "$ac_dir/Makefile" ;; esac fi done fi ;; esac done]], [# Capture the value of obsolete ALL_LINGUAS because we need it to compute # POFILES, UPDATEPOFILES, DUMMYPOFILES, GMOFILES, CATALOGS. But hide it # from automake < 1.5. eval 'OBSOLETE_ALL_LINGUAS''="$ALL_LINGUAS"' # Capture the value of LINGUAS because we need it to compute CATALOGS. LINGUAS="${LINGUAS-%UNSET%}" ]) ]) dnl Postprocesses a Makefile in a directory containing PO files. AC_DEFUN([AM_POSTPROCESS_PO_MAKEFILE], [ # When this code is run, in config.status, two variables have already been # set: # - OBSOLETE_ALL_LINGUAS is the value of LINGUAS set in configure.in, # - LINGUAS is the value of the environment variable LINGUAS at configure # time. changequote(,)dnl # Adjust a relative srcdir. ac_dir=`echo "$ac_file"|sed 's%/[^/][^/]*$%%'` ac_dir_suffix="/`echo "$ac_dir"|sed 's%^\./%%'`" ac_dots=`echo "$ac_dir_suffix"|sed 's%/[^/]*%../%g'` # In autoconf-2.13 it is called $ac_given_srcdir. # In autoconf-2.50 it is called $srcdir. test -n "$ac_given_srcdir" || ac_given_srcdir="$srcdir" case "$ac_given_srcdir" in .) top_srcdir=`echo $ac_dots|sed 's%/$%%'` ;; /*) top_srcdir="$ac_given_srcdir" ;; *) top_srcdir="$ac_dots$ac_given_srcdir" ;; esac # Find a way to echo strings without interpreting backslash. if test "X`(echo '\t') 2>/dev/null`" = 'X\t'; then gt_echo='echo' else if test "X`(printf '%s\n' '\t') 2>/dev/null`" = 'X\t'; then gt_echo='printf %s\n' else echo_func () { cat < "$ac_file.tmp" if grep -l '@TCLCATALOGS@' "$ac_file" > /dev/null; then # Add dependencies that cannot be formulated as a simple suffix rule. for lang in $ALL_LINGUAS; do frobbedlang=`echo $lang | sed -e 's/\..*$//' -e 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/'` cat >> "$ac_file.tmp" < /dev/null; then # Add dependencies that cannot be formulated as a simple suffix rule. for lang in $ALL_LINGUAS; do frobbedlang=`echo $lang | sed -e 's/_/-/g' -e 's/^sr-CS/sr-SP/' -e 's/@latin$/-Latn/' -e 's/@cyrillic$/-Cyrl/' -e 's/^sr-SP$/sr-SP-Latn/' -e 's/^uz-UZ$/uz-UZ-Latn/'` cat >> "$ac_file.tmp" <> "$ac_file.tmp" <, 1996. AC_PREREQ(2.50) # Search path for a program which passes the given test. dnl AM_PATH_PROG_WITH_TEST(VARIABLE, PROG-TO-CHECK-FOR, dnl TEST-PERFORMED-ON-FOUND_PROGRAM [, VALUE-IF-NOT-FOUND [, PATH]]) AC_DEFUN([AM_PATH_PROG_WITH_TEST], [ # Prepare PATH_SEPARATOR. # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then echo "#! /bin/sh" >conf$$.sh echo "exit 0" >>conf$$.sh chmod +x conf$$.sh if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then PATH_SEPARATOR=';' else PATH_SEPARATOR=: fi rm -f conf$$.sh fi # Find out how to test for executable files. Don't use a zero-byte file, # as systems may use methods other than mode bits to determine executability. cat >conf$$.file <<_ASEOF #! /bin/sh exit 0 _ASEOF chmod +x conf$$.file if test -x conf$$.file >/dev/null 2>&1; then ac_executable_p="test -x" else ac_executable_p="test -f" fi rm -f conf$$.file # Extract the first word of "$2", so it can be a program name with args. set dummy $2; ac_word=[$]2 AC_MSG_CHECKING([for $ac_word]) AC_CACHE_VAL(ac_cv_path_$1, [case "[$]$1" in [[\\/]]* | ?:[[\\/]]*) ac_cv_path_$1="[$]$1" # Let the user override the test with a path. ;; *) ac_save_IFS="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in ifelse([$5], , $PATH, [$5]); do IFS="$ac_save_IFS" test -z "$ac_dir" && ac_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $ac_executable_p "$ac_dir/$ac_word$ac_exec_ext"; then echo "$as_me: trying $ac_dir/$ac_word..." >&AS_MESSAGE_LOG_FD if [$3]; then ac_cv_path_$1="$ac_dir/$ac_word$ac_exec_ext" break 2 fi fi done done IFS="$ac_save_IFS" dnl If no 4th arg is given, leave the cache variable unset, dnl so AC_PATH_PROGS will keep looking. ifelse([$4], , , [ test -z "[$]ac_cv_path_$1" && ac_cv_path_$1="$4" ])dnl ;; esac])dnl $1="$ac_cv_path_$1" if test ifelse([$4], , [-n "[$]$1"], ["[$]$1" != "$4"]); then AC_MSG_RESULT([$]$1) else AC_MSG_RESULT(no) fi AC_SUBST($1)dnl ]) partclone-0.2.86/missing000077500000000000000000000153301262102574200152000ustar00rootroot00000000000000#! /bin/sh # Common wrapper for a few potentially missing GNU programs. scriptversion=2013-10-28.13; # UTC # Copyright (C) 1996-2014 Free Software Foundation, Inc. # Originally written by Fran,cois Pinard , 1996. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. if test $# -eq 0; then echo 1>&2 "Try '$0 --help' for more information" exit 1 fi case $1 in --is-lightweight) # Used by our autoconf macros to check whether the available missing # script is modern enough. exit 0 ;; --run) # Back-compat with the calling convention used by older automake. shift ;; -h|--h|--he|--hel|--help) echo "\ $0 [OPTION]... PROGRAM [ARGUMENT]... Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due to PROGRAM being missing or too old. Options: -h, --help display this help and exit -v, --version output version information and exit Supported PROGRAM values: aclocal autoconf autoheader autom4te automake makeinfo bison yacc flex lex help2man Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and 'g' are ignored when checking the name. Send bug reports to ." exit $? ;; -v|--v|--ve|--ver|--vers|--versi|--versio|--version) echo "missing $scriptversion (GNU Automake)" exit $? ;; -*) echo 1>&2 "$0: unknown '$1' option" echo 1>&2 "Try '$0 --help' for more information" exit 1 ;; esac # Run the given program, remember its exit status. "$@"; st=$? # If it succeeded, we are done. test $st -eq 0 && exit 0 # Also exit now if we it failed (or wasn't found), and '--version' was # passed; such an option is passed most likely to detect whether the # program is present and works. case $2 in --version|--help) exit $st;; esac # Exit code 63 means version mismatch. This often happens when the user # tries to use an ancient version of a tool on a file that requires a # minimum version. if test $st -eq 63; then msg="probably too old" elif test $st -eq 127; then # Program was missing. msg="missing on your system" else # Program was found and executed, but failed. Give up. exit $st fi perl_URL=http://www.perl.org/ flex_URL=http://flex.sourceforge.net/ gnu_software_URL=http://www.gnu.org/software program_details () { case $1 in aclocal|automake) echo "The '$1' program is part of the GNU Automake package:" echo "<$gnu_software_URL/automake>" echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:" echo "<$gnu_software_URL/autoconf>" echo "<$gnu_software_URL/m4/>" echo "<$perl_URL>" ;; autoconf|autom4te|autoheader) echo "The '$1' program is part of the GNU Autoconf package:" echo "<$gnu_software_URL/autoconf/>" echo "It also requires GNU m4 and Perl in order to run:" echo "<$gnu_software_URL/m4/>" echo "<$perl_URL>" ;; esac } give_advice () { # Normalize program name to check for. normalized_program=`echo "$1" | sed ' s/^gnu-//; t s/^gnu//; t s/^g//; t'` printf '%s\n' "'$1' is $msg." configure_deps="'configure.ac' or m4 files included by 'configure.ac'" case $normalized_program in autoconf*) echo "You should only need it if you modified 'configure.ac'," echo "or m4 files included by it." program_details 'autoconf' ;; autoheader*) echo "You should only need it if you modified 'acconfig.h' or" echo "$configure_deps." program_details 'autoheader' ;; automake*) echo "You should only need it if you modified 'Makefile.am' or" echo "$configure_deps." program_details 'automake' ;; aclocal*) echo "You should only need it if you modified 'acinclude.m4' or" echo "$configure_deps." program_details 'aclocal' ;; autom4te*) echo "You might have modified some maintainer files that require" echo "the 'autom4te' program to be rebuilt." program_details 'autom4te' ;; bison*|yacc*) echo "You should only need it if you modified a '.y' file." echo "You may want to install the GNU Bison package:" echo "<$gnu_software_URL/bison/>" ;; lex*|flex*) echo "You should only need it if you modified a '.l' file." echo "You may want to install the Fast Lexical Analyzer package:" echo "<$flex_URL>" ;; help2man*) echo "You should only need it if you modified a dependency" \ "of a man page." echo "You may want to install the GNU Help2man package:" echo "<$gnu_software_URL/help2man/>" ;; makeinfo*) echo "You should only need it if you modified a '.texi' file, or" echo "any other file indirectly affecting the aspect of the manual." echo "You might want to install the Texinfo package:" echo "<$gnu_software_URL/texinfo/>" echo "The spurious makeinfo call might also be the consequence of" echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might" echo "want to install GNU make:" echo "<$gnu_software_URL/make/>" ;; *) echo "You might have modified some files without having the proper" echo "tools for further handling them. Check the 'README' file, it" echo "often tells you about the needed prerequisites for installing" echo "this package. You may also peek at any GNU archive site, in" echo "case some other package contains this missing '$1' program." ;; esac } give_advice "$1" | sed -e '1s/^/WARNING: /' \ -e '2,$s/^/ /' >&2 # Propagate the correct exit status (expected to be 127 for a program # not found, 63 for a program that failed due to version mismatch). exit $st # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: partclone-0.2.86/po/000077500000000000000000000000001262102574200142155ustar00rootroot00000000000000partclone-0.2.86/po/ChangeLog000066400000000000000000000007361262102574200157750ustar00rootroot000000000000002007-11-01 gettextize * Makefile.in.in: New file, from gettext-0.16.1. * Rules-quot: New file, from gettext-0.16.1. * boldquot.sed: New file, from gettext-0.16.1. * en@boldquot.header: New file, from gettext-0.16.1. * en@quot.header: New file, from gettext-0.16.1. * insert-header.sin: New file, from gettext-0.16.1. * quot.sed: New file, from gettext-0.16.1. * remove-potcdate.sin: New file, from gettext-0.16.1. * POTFILES.in: New file. partclone-0.2.86/po/LINGUAS000066400000000000000000000000251262102574200152370ustar00rootroot00000000000000zh_TW fr_FR vi zh_CN partclone-0.2.86/po/Makefile.in.in000066400000000000000000000332211262102574200166700ustar00rootroot00000000000000# Makefile for PO directory in any package using GNU gettext. # Copyright (C) 1995-1997, 2000-2006 by Ulrich Drepper # # This file can be copied and used freely without restrictions. It can # be used in projects which are not available under the GNU General Public # License but which still want to provide support for the GNU gettext # functionality. # Please note that the actual code of GNU gettext is covered by the GNU # General Public License and is *not* in the public domain. # # Origin: gettext-0.16 PACKAGE = @PACKAGE@ VERSION = @VERSION@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ SHELL = /bin/sh @SET_MAKE@ srcdir = @srcdir@ top_srcdir = @top_srcdir@ VPATH = @srcdir@ prefix = @prefix@ exec_prefix = @exec_prefix@ datarootdir = @datarootdir@ datadir = @datadir@ localedir = @localedir@ gettextsrcdir = $(datadir)/gettext/po INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ # We use $(mkdir_p). # In automake <= 1.9.x, $(mkdir_p) is defined either as "mkdir -p --" or as # "$(mkinstalldirs)" or as "$(install_sh) -d". For these automake versions, # @install_sh@ does not start with $(SHELL), so we add it. # In automake >= 1.10, @mkdir_p@ is derived from ${MKDIR_P}, which is defined # either as "/path/to/mkdir -p" or ".../install-sh -c -d". For these automake # versions, $(mkinstalldirs) and $(install_sh) are unused. mkinstalldirs = $(SHELL) @install_sh@ -d install_sh = $(SHELL) @install_sh@ MKDIR_P = @MKDIR_P@ mkdir_p = @mkdir_p@ GMSGFMT_ = @GMSGFMT@ GMSGFMT_no = @GMSGFMT@ GMSGFMT_yes = @GMSGFMT_015@ GMSGFMT = $(GMSGFMT_$(USE_MSGCTXT)) MSGFMT_ = @MSGFMT@ MSGFMT_no = @MSGFMT@ MSGFMT_yes = @MSGFMT_015@ MSGFMT = $(MSGFMT_$(USE_MSGCTXT)) XGETTEXT_ = @XGETTEXT@ XGETTEXT_no = @XGETTEXT@ XGETTEXT_yes = @XGETTEXT_015@ XGETTEXT = $(XGETTEXT_$(USE_MSGCTXT)) MSGMERGE = msgmerge MSGMERGE_UPDATE = @MSGMERGE@ --update MSGINIT = msginit MSGCONV = msgconv MSGFILTER = msgfilter POFILES = @POFILES@ GMOFILES = @GMOFILES@ UPDATEPOFILES = @UPDATEPOFILES@ DUMMYPOFILES = @DUMMYPOFILES@ DISTFILES.common = Makefile.in.in remove-potcdate.sin \ $(DISTFILES.common.extra1) $(DISTFILES.common.extra2) $(DISTFILES.common.extra3) DISTFILES = $(DISTFILES.common) Makevars POTFILES.in \ $(POFILES) $(GMOFILES) \ $(DISTFILES.extra1) $(DISTFILES.extra2) $(DISTFILES.extra3) POTFILES = \ CATALOGS = @CATALOGS@ # Makevars gets inserted here. (Don't remove this line!) .SUFFIXES: .SUFFIXES: .po .gmo .mo .sed .sin .nop .po-create .po-update .po.mo: @echo "$(MSGFMT) -c -o $@ $<"; \ $(MSGFMT) -c -o t-$@ $< && mv t-$@ $@ .po.gmo: @lang=`echo $* | sed -e 's,.*/,,'`; \ test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ echo "$${cdcmd}rm -f $${lang}.gmo && $(GMSGFMT) -c --statistics -o $${lang}.gmo $${lang}.po"; \ cd $(srcdir) && rm -f $${lang}.gmo && $(GMSGFMT) -c --statistics -o t-$${lang}.gmo $${lang}.po && mv t-$${lang}.gmo $${lang}.gmo .sin.sed: sed -e '/^#/d' $< > t-$@ mv t-$@ $@ all: all-@USE_NLS@ all-yes: stamp-po all-no: # $(srcdir)/$(DOMAIN).pot is only created when needed. When xgettext finds no # internationalized messages, no $(srcdir)/$(DOMAIN).pot is created (because # we don't want to bother translators with empty POT files). We assume that # LINGUAS is empty in this case, i.e. $(POFILES) and $(GMOFILES) are empty. # In this case, stamp-po is a nop (i.e. a phony target). # stamp-po is a timestamp denoting the last time at which the CATALOGS have # been loosely updated. Its purpose is that when a developer or translator # checks out the package via CVS, and the $(DOMAIN).pot file is not in CVS, # "make" will update the $(DOMAIN).pot and the $(CATALOGS), but subsequent # invocations of "make" will do nothing. This timestamp would not be necessary # if updating the $(CATALOGS) would always touch them; however, the rule for # $(POFILES) has been designed to not touch files that don't need to be # changed. stamp-po: $(srcdir)/$(DOMAIN).pot test ! -f $(srcdir)/$(DOMAIN).pot || \ test -z "$(GMOFILES)" || $(MAKE) $(GMOFILES) @test ! -f $(srcdir)/$(DOMAIN).pot || { \ echo "touch stamp-po" && \ echo timestamp > stamp-poT && \ mv stamp-poT stamp-po; \ } # Note: Target 'all' must not depend on target '$(DOMAIN).pot-update', # otherwise packages like GCC can not be built if only parts of the source # have been downloaded. # This target rebuilds $(DOMAIN).pot; it is an expensive operation. # Note that $(DOMAIN).pot is not touched if it doesn't need to be changed. $(DOMAIN).pot-update: $(POTFILES) $(srcdir)/POTFILES.in remove-potcdate.sed if test -n '$(MSGID_BUGS_ADDRESS)' || test '$(PACKAGE_BUGREPORT)' = '@'PACKAGE_BUGREPORT'@'; then \ msgid_bugs_address='$(MSGID_BUGS_ADDRESS)'; \ else \ msgid_bugs_address='$(PACKAGE_BUGREPORT)'; \ fi; \ $(XGETTEXT) --default-domain=$(DOMAIN) --directory=$(top_srcdir) \ --add-comments=TRANSLATORS: $(XGETTEXT_OPTIONS) \ --files-from=$(srcdir)/POTFILES.in \ --copyright-holder='$(COPYRIGHT_HOLDER)' \ --msgid-bugs-address="$$msgid_bugs_address" test ! -f $(DOMAIN).po || { \ if test -f $(srcdir)/$(DOMAIN).pot; then \ sed -f remove-potcdate.sed < $(srcdir)/$(DOMAIN).pot > $(DOMAIN).1po && \ sed -f remove-potcdate.sed < $(DOMAIN).po > $(DOMAIN).2po && \ if cmp $(DOMAIN).1po $(DOMAIN).2po >/dev/null 2>&1; then \ rm -f $(DOMAIN).1po $(DOMAIN).2po $(DOMAIN).po; \ else \ rm -f $(DOMAIN).1po $(DOMAIN).2po $(srcdir)/$(DOMAIN).pot && \ mv $(DOMAIN).po $(srcdir)/$(DOMAIN).pot; \ fi; \ else \ mv $(DOMAIN).po $(srcdir)/$(DOMAIN).pot; \ fi; \ } # This rule has no dependencies: we don't need to update $(DOMAIN).pot at # every "make" invocation, only create it when it is missing. # Only "make $(DOMAIN).pot-update" or "make dist" will force an update. $(srcdir)/$(DOMAIN).pot: $(MAKE) $(DOMAIN).pot-update # This target rebuilds a PO file if $(DOMAIN).pot has changed. # Note that a PO file is not touched if it doesn't need to be changed. $(POFILES): $(srcdir)/$(DOMAIN).pot @lang=`echo $@ | sed -e 's,.*/,,' -e 's/\.po$$//'`; \ if test -f "$(srcdir)/$${lang}.po"; then \ test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ echo "$${cdcmd}$(MSGMERGE_UPDATE) $${lang}.po $(DOMAIN).pot"; \ cd $(srcdir) && $(MSGMERGE_UPDATE) $${lang}.po $(DOMAIN).pot; \ else \ $(MAKE) $${lang}.po-create; \ fi install: install-exec install-data install-exec: install-data: install-data-@USE_NLS@ if test "$(PACKAGE)" = "gettext-tools"; then \ $(mkdir_p) $(DESTDIR)$(gettextsrcdir); \ for file in $(DISTFILES.common) Makevars.template; do \ $(INSTALL_DATA) $(srcdir)/$$file \ $(DESTDIR)$(gettextsrcdir)/$$file; \ done; \ for file in Makevars; do \ rm -f $(DESTDIR)$(gettextsrcdir)/$$file; \ done; \ else \ : ; \ fi install-data-no: all install-data-yes: all $(mkdir_p) $(DESTDIR)$(datadir) @catalogs='$(CATALOGS)'; \ for cat in $$catalogs; do \ cat=`basename $$cat`; \ lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \ dir=$(localedir)/$$lang/LC_MESSAGES; \ $(mkdir_p) $(DESTDIR)$$dir; \ if test -r $$cat; then realcat=$$cat; else realcat=$(srcdir)/$$cat; fi; \ $(INSTALL_DATA) $$realcat $(DESTDIR)$$dir/$(DOMAIN).mo; \ echo "installing $$realcat as $(DESTDIR)$$dir/$(DOMAIN).mo"; \ for lc in '' $(EXTRA_LOCALE_CATEGORIES); do \ if test -n "$$lc"; then \ if (cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc 2>/dev/null) | grep ' -> ' >/dev/null; then \ link=`cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc | sed -e 's/^.* -> //'`; \ mv $(DESTDIR)$(localedir)/$$lang/$$lc $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ (cd $(DESTDIR)$(localedir)/$$lang/$$lc.old && \ for file in *; do \ if test -f $$file; then \ ln -s ../$$link/$$file $(DESTDIR)$(localedir)/$$lang/$$lc/$$file; \ fi; \ done); \ rm -f $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ else \ if test -d $(DESTDIR)$(localedir)/$$lang/$$lc; then \ :; \ else \ rm -f $(DESTDIR)$(localedir)/$$lang/$$lc; \ mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ fi; \ fi; \ rm -f $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \ ln -s ../LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo 2>/dev/null || \ ln $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo 2>/dev/null || \ cp -p $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(DOMAIN).mo $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \ echo "installing $$realcat link as $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo"; \ fi; \ done; \ done install-strip: install installdirs: installdirs-exec installdirs-data installdirs-exec: installdirs-data: installdirs-data-@USE_NLS@ if test "$(PACKAGE)" = "gettext-tools"; then \ $(mkdir_p) $(DESTDIR)$(gettextsrcdir); \ else \ : ; \ fi installdirs-data-no: installdirs-data-yes: $(mkdir_p) $(DESTDIR)$(datadir) @catalogs='$(CATALOGS)'; \ for cat in $$catalogs; do \ cat=`basename $$cat`; \ lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \ dir=$(localedir)/$$lang/LC_MESSAGES; \ $(mkdir_p) $(DESTDIR)$$dir; \ for lc in '' $(EXTRA_LOCALE_CATEGORIES); do \ if test -n "$$lc"; then \ if (cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc 2>/dev/null) | grep ' -> ' >/dev/null; then \ link=`cd $(DESTDIR)$(localedir)/$$lang && LC_ALL=C ls -l -d $$lc | sed -e 's/^.* -> //'`; \ mv $(DESTDIR)$(localedir)/$$lang/$$lc $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ (cd $(DESTDIR)$(localedir)/$$lang/$$lc.old && \ for file in *; do \ if test -f $$file; then \ ln -s ../$$link/$$file $(DESTDIR)$(localedir)/$$lang/$$lc/$$file; \ fi; \ done); \ rm -f $(DESTDIR)$(localedir)/$$lang/$$lc.old; \ else \ if test -d $(DESTDIR)$(localedir)/$$lang/$$lc; then \ :; \ else \ rm -f $(DESTDIR)$(localedir)/$$lang/$$lc; \ mkdir $(DESTDIR)$(localedir)/$$lang/$$lc; \ fi; \ fi; \ fi; \ done; \ done # Define this as empty until I found a useful application. installcheck: uninstall: uninstall-exec uninstall-data uninstall-exec: uninstall-data: uninstall-data-@USE_NLS@ if test "$(PACKAGE)" = "gettext-tools"; then \ for file in $(DISTFILES.common) Makevars.template; do \ rm -f $(DESTDIR)$(gettextsrcdir)/$$file; \ done; \ else \ : ; \ fi uninstall-data-no: uninstall-data-yes: catalogs='$(CATALOGS)'; \ for cat in $$catalogs; do \ cat=`basename $$cat`; \ lang=`echo $$cat | sed -e 's/\.gmo$$//'`; \ for lc in LC_MESSAGES $(EXTRA_LOCALE_CATEGORIES); do \ rm -f $(DESTDIR)$(localedir)/$$lang/$$lc/$(DOMAIN).mo; \ done; \ done check: all info dvi ps pdf html tags TAGS ctags CTAGS ID: mostlyclean: rm -f remove-potcdate.sed rm -f stamp-poT rm -f core core.* $(DOMAIN).po $(DOMAIN).1po $(DOMAIN).2po *.new.po rm -fr *.o clean: mostlyclean distclean: clean rm -f Makefile Makefile.in POTFILES *.mo maintainer-clean: distclean @echo "This command is intended for maintainers to use;" @echo "it deletes files that may require special tools to rebuild." rm -f stamp-po $(GMOFILES) distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) dist distdir: $(MAKE) update-po @$(MAKE) dist2 # This is a separate target because 'update-po' must be executed before. dist2: stamp-po $(DISTFILES) dists="$(DISTFILES)"; \ if test "$(PACKAGE)" = "gettext-tools"; then \ dists="$$dists Makevars.template"; \ fi; \ if test -f $(srcdir)/$(DOMAIN).pot; then \ dists="$$dists $(DOMAIN).pot stamp-po"; \ fi; \ if test -f $(srcdir)/ChangeLog; then \ dists="$$dists ChangeLog"; \ fi; \ for i in 0 1 2 3 4 5 6 7 8 9; do \ if test -f $(srcdir)/ChangeLog.$$i; then \ dists="$$dists ChangeLog.$$i"; \ fi; \ done; \ if test -f $(srcdir)/LINGUAS; then dists="$$dists LINGUAS"; fi; \ for file in $$dists; do \ if test -f $$file; then \ cp -p $$file $(distdir) || exit 1; \ else \ cp -p $(srcdir)/$$file $(distdir) || exit 1; \ fi; \ done update-po: Makefile $(MAKE) $(DOMAIN).pot-update test -z "$(UPDATEPOFILES)" || $(MAKE) $(UPDATEPOFILES) $(MAKE) update-gmo # General rule for creating PO files. .nop.po-create: @lang=`echo $@ | sed -e 's/\.po-create$$//'`; \ echo "File $$lang.po does not exist. If you are a translator, you can create it through 'msginit'." 1>&2; \ exit 1 # General rule for updating PO files. .nop.po-update: @lang=`echo $@ | sed -e 's/\.po-update$$//'`; \ if test "$(PACKAGE)" = "gettext-tools"; then PATH=`pwd`/../src:$$PATH; fi; \ tmpdir=`pwd`; \ echo "$$lang:"; \ test "$(srcdir)" = . && cdcmd="" || cdcmd="cd $(srcdir) && "; \ echo "$${cdcmd}$(MSGMERGE) $$lang.po $(DOMAIN).pot -o $$lang.new.po"; \ cd $(srcdir); \ if $(MSGMERGE) $$lang.po $(DOMAIN).pot -o $$tmpdir/$$lang.new.po; then \ if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ rm -f $$tmpdir/$$lang.new.po; \ else \ if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ :; \ else \ echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ exit 1; \ fi; \ fi; \ else \ echo "msgmerge for $$lang.po failed!" 1>&2; \ rm -f $$tmpdir/$$lang.new.po; \ fi $(DUMMYPOFILES): update-gmo: Makefile $(GMOFILES) @: Makefile: Makefile.in.in Makevars $(top_builddir)/config.status @POMAKEFILEDEPS@ cd $(top_builddir) \ && $(SHELL) ./config.status $(subdir)/$@.in po-directories force: # Tell versions [3.59,3.63) of GNU make not to export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: partclone-0.2.86/po/Makevars000066400000000000000000000034271262102574200157170ustar00rootroot00000000000000# Makefile variables for PO directory in any package using GNU gettext. # Usually the message domain is the same as the package name. DOMAIN = $(PACKAGE) # These two variables depend on the location of this directory. subdir = po top_builddir = .. # These options get passed to xgettext. XGETTEXT_OPTIONS = --keyword=_ --keyword=N_ # This is the copyright holder that gets inserted into the header of the # $(DOMAIN).pot file. Set this to the copyright holder of the surrounding # package. (Note that the msgstr strings, extracted from the package's # sources, belong to the copyright holder of the package.) Translators are # expected to transfer the copyright for their translations to this person # or entity, or to disclaim their copyright. The empty string stands for # the public domain; in this case the translators are expected to disclaim # their copyright. COPYRIGHT_HOLDER = thomas@nchc.org.tw # This is the email address or URL to which the translators shall report # bugs in the untranslated strings: # - Strings which are not entire sentences, see the maintainer guidelines # in the GNU gettext documentation, section 'Preparing Strings'. # - Strings which use unclear terms or require additional context to be # understood. # - Strings which make invalid assumptions about notation of date, time or # money. # - Pluralisation problems. # - Incorrect English spelling. # - Incorrect formatting. # It can be your email address, or a mailing list address where translators # can write to without being subscribed, or the URL of a web page through # which the translators can contact you. MSGID_BUGS_ADDRESS = $(PACKAGE BUGREPORT) # This is the list of locale categories, beyond LC_MESSAGES, for which the # message catalogs shall be used. It is usually empty. EXTRA_LOCALE_CATEGORIES = partclone-0.2.86/po/POTFILES000066400000000000000000000000611262102574200153620ustar00rootroot00000000000000 ../src/progress.c \ ../src/partclone.c partclone-0.2.86/po/POTFILES.in000066400000000000000000000001321262102574200157660ustar00rootroot00000000000000# List of source files which contain translatable strings. src/progress.c src/partclone.c partclone-0.2.86/po/Rules-quot000066400000000000000000000033761262102574200162310ustar00rootroot00000000000000# Special Makefile rules for English message catalogs with quotation marks. DISTFILES.common.extra1 = quot.sed boldquot.sed en@quot.header en@boldquot.header insert-header.sin Rules-quot .SUFFIXES: .insert-header .po-update-en en@quot.po-create: $(MAKE) en@quot.po-update en@boldquot.po-create: $(MAKE) en@boldquot.po-update en@quot.po-update: en@quot.po-update-en en@boldquot.po-update: en@boldquot.po-update-en .insert-header.po-update-en: @lang=`echo $@ | sed -e 's/\.po-update-en$$//'`; \ if test "$(PACKAGE)" = "gettext"; then PATH=`pwd`/../src:$$PATH; GETTEXTLIBDIR=`cd $(top_srcdir)/src && pwd`; export GETTEXTLIBDIR; fi; \ tmpdir=`pwd`; \ echo "$$lang:"; \ ll=`echo $$lang | sed -e 's/@.*//'`; \ LC_ALL=C; export LC_ALL; \ cd $(srcdir); \ if $(MSGINIT) -i $(DOMAIN).pot --no-translator -l $$ll -o - 2>/dev/null | sed -f $$tmpdir/$$lang.insert-header | $(MSGCONV) -t UTF-8 | $(MSGFILTER) sed -f `echo $$lang | sed -e 's/.*@//'`.sed 2>/dev/null > $$tmpdir/$$lang.new.po; then \ if cmp $$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ rm -f $$tmpdir/$$lang.new.po; \ else \ if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ :; \ else \ echo "creation of $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ exit 1; \ fi; \ fi; \ else \ echo "creation of $$lang.po failed!" 1>&2; \ rm -f $$tmpdir/$$lang.new.po; \ fi en@quot.insert-header: insert-header.sin sed -e '/^#/d' -e 's/HEADER/en@quot.header/g' $(srcdir)/insert-header.sin > en@quot.insert-header en@boldquot.insert-header: insert-header.sin sed -e '/^#/d' -e 's/HEADER/en@boldquot.header/g' $(srcdir)/insert-header.sin > en@boldquot.insert-header mostlyclean: mostlyclean-quot mostlyclean-quot: rm -f *.insert-header partclone-0.2.86/po/boldquot.sed000066400000000000000000000003311262102574200165400ustar00rootroot00000000000000s/"\([^"]*\)"/“\1â€/g s/`\([^`']*\)'/‘\1’/g s/ '\([^`']*\)' / ‘\1’ /g s/ '\([^`']*\)'$/ ‘\1’/g s/^'\([^`']*\)' /‘\1’ /g s/“â€/""/g s/“/“/g s/â€/â€/g s/‘/‘/g s/’/’/g partclone-0.2.86/po/en@boldquot.header000066400000000000000000000024711262102574200176470ustar00rootroot00000000000000# All this catalog "translates" are quotation characters. # The msgids must be ASCII and therefore cannot contain real quotation # characters, only substitutes like grave accent (0x60), apostrophe (0x27) # and double quote (0x22). These substitutes look strange; see # http://www.cl.cam.ac.uk/~mgk25/ucs/quotes.html # # This catalog translates grave accent (0x60) and apostrophe (0x27) to # left single quotation mark (U+2018) and right single quotation mark (U+2019). # It also translates pairs of apostrophe (0x27) to # left single quotation mark (U+2018) and right single quotation mark (U+2019) # and pairs of quotation mark (0x22) to # left double quotation mark (U+201C) and right double quotation mark (U+201D). # # When output to an UTF-8 terminal, the quotation characters appear perfectly. # When output to an ISO-8859-1 terminal, the single quotation marks are # transliterated to apostrophes (by iconv in glibc 2.2 or newer) or to # grave/acute accent (by libiconv), and the double quotation marks are # transliterated to 0x22. # When output to an ASCII terminal, the single quotation marks are # transliterated to apostrophes, and the double quotation marks are # transliterated to 0x22. # # This catalog furthermore displays the text between the quotation marks in # bold face, assuming the VT100/XTerm escape sequences. # partclone-0.2.86/po/en@quot.header000066400000000000000000000022631262102574200170050ustar00rootroot00000000000000# All this catalog "translates" are quotation characters. # The msgids must be ASCII and therefore cannot contain real quotation # characters, only substitutes like grave accent (0x60), apostrophe (0x27) # and double quote (0x22). These substitutes look strange; see # http://www.cl.cam.ac.uk/~mgk25/ucs/quotes.html # # This catalog translates grave accent (0x60) and apostrophe (0x27) to # left single quotation mark (U+2018) and right single quotation mark (U+2019). # It also translates pairs of apostrophe (0x27) to # left single quotation mark (U+2018) and right single quotation mark (U+2019) # and pairs of quotation mark (0x22) to # left double quotation mark (U+201C) and right double quotation mark (U+201D). # # When output to an UTF-8 terminal, the quotation characters appear perfectly. # When output to an ISO-8859-1 terminal, the single quotation marks are # transliterated to apostrophes (by iconv in glibc 2.2 or newer) or to # grave/acute accent (by libiconv), and the double quotation marks are # transliterated to 0x22. # When output to an ASCII terminal, the single quotation marks are # transliterated to apostrophes, and the double quotation marks are # transliterated to 0x22. # partclone-0.2.86/po/fr_FR.gmo000066400000000000000000000041451262102574200157230ustar00rootroot00000000000000Þ•´LÀÁ4Ó /H_vAˆ@ÊB #Nr-„²,Ð.ýk,˜3­á äñ"<XQsGÅJ #X|CÓ7ð<(    Total Time: %s, %80c Elapsed: %s, Remaining: %s, Completed: %6.2f%%%s, %6.2f%s/min,, Rate: %6.2f%s/min,Ave. Rate: %6.1f%s/min, Ave. Rate: %6.2f%s/minBlock size: %i Byte File system: %s Partclone successfully cloned the device (%s) to the device (%s) Partclone successfully cloned the device (%s) to the image (%s) Partclone successfully restored the image (%s) to the device (%s) Partclone v%s http://partclone.org Rate: %6.2f%s/minStarting to back up device(%s) to device(%s) Starting to check image (%s) Starting to clone device (%s) to image (%s) Starting to restore image (%s) to device (%s) Project-Id-Version: Partclone 0.2.9 Report-Msgid-Bugs-To: thomas@nchc.org.tw POT-Creation-Date: 2015-09-24 10:11+0800 PO-Revision-Date: 2010-11-01 10:13+0100 Last-Translator: Language-Team: French Language: fr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Plural-Forms: nplurals=2; plural=(n > 1); Durée totale: %s, %80c Ecoulé: %s, Restant: %s, Complété:%6.2f%%,%s, %6.2f%s/mn, Débit: %6.2f%s/mn,Débit moyen: %6.1f%s/mn, Débit moyen: %6.2f%s/minTaille de bloc: %i octets Système de fichiers: %s Partclone a réussi à cloner le périphérique (%s) vers le périphérique (%s) Partclone a réussi à cloner le périphérique (%s) vers l'image (%s) Partclone a réussi à restaurer l'image (%s) vers le périphérique (%s) Partclone v%s http://partclone.org Débit: %6.2f%s/mnDémarrage sauvegarde périphérique (%s) vers périphérique (%s) Démarrage audit image (%s) Démarrage clonage périphérique (%s) vers image (%s) Démarrage restauration image (%s) vers périphérique (%s) partclone-0.2.86/po/fr_FR.po000066400000000000000000000133771262102574200155660ustar00rootroot00000000000000# French translations for Partclone package # Traductions françaises du paquet Partclone. # Copyright (C) 2010 thomas@nchc.org.tw # This file is distributed under the same license as the Partclone package. # Cédric OLLIVIER , 2010. # msgid "" msgstr "" "Project-Id-Version: Partclone 0.2.9\n" "Report-Msgid-Bugs-To: thomas@nchc.org.tw\n" "POT-Creation-Date: 2015-09-24 10:11+0800\n" "PO-Revision-Date: 2010-11-01 10:13+0100\n" "Last-Translator: \n" "Language-Team: French \n" "Language: fr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" #: src/progress.c:200 #, c-format msgid "\r%80c\rElapsed: %s, Remaining: %s, Completed: %6.2f%%" msgstr "\r%80c\rEcoulé: %s, Restant: %s, Complété:%6.2f%%," #: src/progress.c:203 #, c-format msgid ", %6.2f%s/min," msgstr ", %6.2f%s/mn" #: src/progress.c:211 #, fuzzy, c-format msgid "\r%80c\rElapsed: %s, Remaining: %s, Completed: 100.00%%" msgstr "\r%80c\rEcoulé: %s, Restant: %s, Complété:%6.2f%%," #: src/progress.c:213 #, c-format msgid ", Rate: %6.2f%s/min," msgstr ", Débit: %6.2f%s/mn," #: src/progress.c:217 #, c-format msgid "" "\n" "Total Time: %s, " msgstr "" "\n" "Durée totale: %s, " #: src/progress.c:219 #, c-format msgid "Ave. Rate: %6.1f%s/min, " msgstr "Débit moyen: %6.1f%s/mn, " #: src/progress.c:220 #, c-format msgid "%s" msgstr "%s" #: src/progress.c:247 #, fuzzy, c-format msgid "Elapsed: %s Remaining: %s " msgstr "" " Ecoulé: %s\n" " Restant: %s\n" " Complété:%6.2f%%" #: src/progress.c:249 #, c-format msgid "Rate: %6.2f%s/min" msgstr "Débit: %6.2f%s/mn" #: src/progress.c:251 #, c-format msgid "Current Block: %llu Total Block: %llu " msgstr "" #: src/progress.c:282 #, fuzzy, c-format msgid "Total Time: %s Remaining: %s " msgstr "" "\n" "Durée totale: %s, " #: src/progress.c:284 #, c-format msgid "Ave. Rate: %6.2f%s/min" msgstr "Débit moyen: %6.2f%s/min" #: src/partclone.c:1094 #, c-format msgid "Partclone v%s http://partclone.org\n" msgstr "Partclone v%s http://partclone.org\n" #: src/partclone.c:1096 #, c-format msgid "Starting to check image (%s)\n" msgstr "Démarrage audit image (%s)\n" #: src/partclone.c:1098 #, c-format msgid "Starting to clone device (%s) to image (%s)\n" msgstr "Démarrage clonage périphérique (%s) vers image (%s)\n" #: src/partclone.c:1100 #, c-format msgid "Starting to restore image (%s) to device (%s)\n" msgstr "Démarrage restauration image (%s) vers périphérique (%s)\n" #: src/partclone.c:1102 #, c-format msgid "Starting to back up device(%s) to device(%s)\n" msgstr "Démarrage sauvegarde périphérique (%s) vers périphérique (%s)\n" #: src/partclone.c:1104 #, fuzzy, c-format msgid "Starting to map device (%s) to domain log (%s)\n" msgstr "Démarrage clonage périphérique (%s) vers image (%s)\n" #: src/partclone.c:1106 #, fuzzy, c-format msgid "Starting to clone/restore (%s) to (%s) with dd mode\n" msgstr "Démarrage clonage périphérique (%s) vers image (%s)\n" #: src/partclone.c:1108 msgid "Display image information\n" msgstr "" #: src/partclone.c:1129 #, c-format msgid "File system: %s\n" msgstr "Système de fichiers: %s\n" #: src/partclone.c:1132 #, fuzzy, c-format msgid "Device size: %s = %llu Blocks\n" msgstr "Taille du périphérique: %s\n" #: src/partclone.c:1135 #, fuzzy, c-format msgid "Space in use: %s = %llu Blocks\n" msgstr "Espace utilisé: %s\n" #: src/partclone.c:1138 #, fuzzy, c-format msgid "Free Space: %s = %llu Blocks\n" msgstr "Espace libre: %s\n" #: src/partclone.c:1140 #, c-format msgid "Block size: %i Byte\n" msgstr "Taille de bloc: %i octets\n" #: src/partclone.c:1152 #, fuzzy, c-format msgid "Partclone successfully checked the image (%s)\n" msgstr "Partclone a réussi à auditer l'image (%s)\n" #: src/partclone.c:1154 #, c-format msgid "Partclone successfully cloned the device (%s) to the image (%s)\n" msgstr "Partclone a réussi à cloner le périphérique (%s) vers l'image (%s)\n" #: src/partclone.c:1156 #, c-format msgid "Partclone successfully restored the image (%s) to the device (%s)\n" msgstr "" "Partclone a réussi à restaurer l'image (%s) vers le périphérique (%s)\n" #: src/partclone.c:1158 #, c-format msgid "Partclone successfully cloned the device (%s) to the device (%s)\n" msgstr "" "Partclone a réussi à cloner le périphérique (%s) vers le périphérique (%s)\n" #: src/partclone.c:1160 #, fuzzy, c-format msgid "Partclone successfully mapped the device (%s) to the domain log (%s)\n" msgstr "Partclone a réussi à cloner le périphérique (%s) vers l'image (%s)\n" #~ msgid "\r%80c\rElapsed: %s, Remaining: %s, Completed:%6.2f%%, Seeking...," #~ msgstr "\r%80c\rEcoulé: %s, Restant: %s, Complété:%6.2f%%, Recherche...," #~ msgid "" #~ "\r%80c\rElapsed: %s, Remaining: %s, Completed:%6.2f%%, Rate: %6.2f%s/min," #~ msgstr "" #~ "\r%80c\rEcoulé: %s, Restant: %s, Complété:%6.2f%%, Débit: %6.2f%s/mn," #~ msgid " " #~ msgstr " " #~ msgid "Elapsed: %s" #~ msgstr "Ecoulé: %s" #~ msgid "Remaining: %s" #~ msgstr "Restant: %s" #~ msgid "Total Time: %s" #~ msgstr "Durée totale: %s" #~ msgid "Remaining: 0" #~ msgstr "Restant: 0" #~ msgid "" #~ " Elapsed: %s\n" #~ " Remaining: %s\n" #~ " Completed:%6.2f%%\n" #~ " Rate: %6.2f%s/min, " #~ msgstr "" #~ " Ecoulé: %s\n" #~ " Restant: %s\n" #~ " Complété:%6.2f%%\n" #~ " Débit: %6.2f%s/min, " #~ msgid "" #~ " Total Time: %s\n" #~ " Ave. Rate: %6.1f%s/min\n" #~ " 100.00%% completed!\n" #~ msgstr "" #~ " Durée totale: %s\n" #~ " Débit moyen: %6.1f%s/min\n" #~ " 100.00%% d'achèvement!\n" #~ msgid "" #~ " Total Time: %s\n" #~ " 100.00%% completed!\n" #~ msgstr "" #~ " Durée totale: %s\n" #~ " 100.00%% d'achèvement!\n" #~ msgid "Used block : %lli\n" #~ msgstr "Blocs utilisés : %lli\n" partclone-0.2.86/po/insert-header.sin000066400000000000000000000012401262102574200174570ustar00rootroot00000000000000# Sed script that inserts the file called HEADER before the header entry. # # At each occurrence of a line starting with "msgid ", we execute the following # commands. At the first occurrence, insert the file. At the following # occurrences, do nothing. The distinction between the first and the following # occurrences is achieved by looking at the hold space. /^msgid /{ x # Test if the hold space is empty. s/m/m/ ta # Yes it was empty. First occurrence. Read the file. r HEADER # Output the file's contents by reading the next line. But don't lose the # current line while doing this. g N bb :a # The hold space was nonempty. Following occurrences. Do nothing. x :b } partclone-0.2.86/po/partclone.pot000066400000000000000000000064161262102574200167370ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR thomas@nchc.org.tw # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: thomas@nchc.org.tw\n" "POT-Creation-Date: 2015-09-24 10:11+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" #: src/progress.c:200 #, c-format msgid "\r%80c\rElapsed: %s, Remaining: %s, Completed: %6.2f%%" msgstr "" #: src/progress.c:203 #, c-format msgid ", %6.2f%s/min," msgstr "" #: src/progress.c:211 #, c-format msgid "\r%80c\rElapsed: %s, Remaining: %s, Completed: 100.00%%" msgstr "" #: src/progress.c:213 #, c-format msgid ", Rate: %6.2f%s/min," msgstr "" #: src/progress.c:217 #, c-format msgid "" "\n" "Total Time: %s, " msgstr "" #: src/progress.c:219 #, c-format msgid "Ave. Rate: %6.1f%s/min, " msgstr "" #: src/progress.c:220 #, c-format msgid "%s" msgstr "" #: src/progress.c:247 #, c-format msgid "Elapsed: %s Remaining: %s " msgstr "" #: src/progress.c:249 #, c-format msgid "Rate: %6.2f%s/min" msgstr "" #: src/progress.c:251 #, c-format msgid "Current Block: %llu Total Block: %llu " msgstr "" #: src/progress.c:282 #, c-format msgid "Total Time: %s Remaining: %s " msgstr "" #: src/progress.c:284 #, c-format msgid "Ave. Rate: %6.2f%s/min" msgstr "" #: src/partclone.c:1094 #, c-format msgid "Partclone v%s http://partclone.org\n" msgstr "" #: src/partclone.c:1096 #, c-format msgid "Starting to check image (%s)\n" msgstr "" #: src/partclone.c:1098 #, c-format msgid "Starting to clone device (%s) to image (%s)\n" msgstr "" #: src/partclone.c:1100 #, c-format msgid "Starting to restore image (%s) to device (%s)\n" msgstr "" #: src/partclone.c:1102 #, c-format msgid "Starting to back up device(%s) to device(%s)\n" msgstr "" #: src/partclone.c:1104 #, c-format msgid "Starting to map device (%s) to domain log (%s)\n" msgstr "" #: src/partclone.c:1106 #, c-format msgid "Starting to clone/restore (%s) to (%s) with dd mode\n" msgstr "" #: src/partclone.c:1108 msgid "Display image information\n" msgstr "" #: src/partclone.c:1129 #, c-format msgid "File system: %s\n" msgstr "" #: src/partclone.c:1132 #, c-format msgid "Device size: %s = %llu Blocks\n" msgstr "" #: src/partclone.c:1135 #, c-format msgid "Space in use: %s = %llu Blocks\n" msgstr "" #: src/partclone.c:1138 #, c-format msgid "Free Space: %s = %llu Blocks\n" msgstr "" #: src/partclone.c:1140 #, c-format msgid "Block size: %i Byte\n" msgstr "" #: src/partclone.c:1152 #, c-format msgid "Partclone successfully checked the image (%s)\n" msgstr "" #: src/partclone.c:1154 #, c-format msgid "Partclone successfully cloned the device (%s) to the image (%s)\n" msgstr "" #: src/partclone.c:1156 #, c-format msgid "Partclone successfully restored the image (%s) to the device (%s)\n" msgstr "" #: src/partclone.c:1158 #, c-format msgid "Partclone successfully cloned the device (%s) to the device (%s)\n" msgstr "" #: src/partclone.c:1160 #, c-format msgid "Partclone successfully mapped the device (%s) to the domain log (%s)\n" msgstr "" partclone-0.2.86/po/quot.sed000066400000000000000000000002311262102574200156760ustar00rootroot00000000000000s/"\([^"]*\)"/“\1â€/g s/`\([^`']*\)'/‘\1’/g s/ '\([^`']*\)' / ‘\1’ /g s/ '\([^`']*\)'$/ ‘\1’/g s/^'\([^`']*\)' /‘\1’ /g s/“â€/""/g partclone-0.2.86/po/remove-potcdate.sed000066400000000000000000000000721262102574200200070ustar00rootroot00000000000000/^"POT-Creation-Date: .*"$/{ x s/P/P/ ta g d bb :a x :b } partclone-0.2.86/po/remove-potcdate.sin000066400000000000000000000006601262102574200200300ustar00rootroot00000000000000# Sed script that remove the POT-Creation-Date line in the header entry # from a POT file. # # The distinction between the first and the following occurrences of the # pattern is achieved by looking at the hold space. /^"POT-Creation-Date: .*"$/{ x # Test if the hold space is empty. s/P/P/ ta # Yes it was empty. First occurrence. Remove the line. g d bb :a # The hold space was nonempty. Following occurrences. Do nothing. x :b } partclone-0.2.86/po/stamp-po000066400000000000000000000000121262102574200156710ustar00rootroot00000000000000timestamp partclone-0.2.86/po/vi.gmo000066400000000000000000000066521262102574200153500ustar00rootroot00000000000000Þ•)ì‘4£5Ø 5Ne'|¤Äßñ.A@@‚EÃB #Lp‚-¢Ð,î/.Kz¿˜ X<y=¶ô÷ ' G $g /Œ /¼ !ì  -- 2[ QŽ Là Y- K‡ 1Ó  - JN ™ =¶ Jô <? -|      Total Time: %s, %80c Elapsed: %s, Remaining: %s, Completed: %6.2f%% %80c Elapsed: %s, Remaining: %s, Completed: 100.00%%%s, %6.2f%s/min,, Rate: %6.2f%s/min,Ave. Rate: %6.1f%s/min, Ave. Rate: %6.2f%s/minBlock size: %i Byte Current Block: %llu Total Block: %llu Device size: %s = %llu Blocks Elapsed: %s Remaining: %s File system: %s Free Space: %s = %llu Blocks Partclone successfully checked the image (%s) Partclone successfully cloned the device (%s) to the device (%s) Partclone successfully cloned the device (%s) to the image (%s) Partclone successfully mapped the device (%s) to the domain log (%s) Partclone successfully restored the image (%s) to the device (%s) Partclone v%s http://partclone.org Rate: %6.2f%s/minSpace in use: %s = %llu Blocks Starting to back up device(%s) to device(%s) Starting to check image (%s) Starting to clone device (%s) to image (%s) Starting to map device (%s) to domain log (%s) Starting to restore image (%s) to device (%s) Total Time: %s Remaining: %s Project-Id-Version: partclone-0.2.61 Report-Msgid-Bugs-To: thomas@nchc.org.tw POT-Creation-Date: 2015-09-24 10:11+0800 PO-Revision-Date: 2013-06-13 09:03+0700 Last-Translator: Trần Ngá»c Quân Language-Team: Vietnamese Language: vi MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Generator: Poedit 1.5.5 X-Poedit-SourceCharset: UTF-8 Thá»i gian tổng cá»™ng: %s, %80c Äã được: %s, Còn: %s, Äã hoàn tất: %6.2f%% %80c Äã được: %s, Còn: %s, Äã hoàn tất: 100.00%%%s, %6.2f%s/phút,, Tốc độ: %6.2f%s/phút, Tốc độ tb: %6.1f%s/phút, Tốc độ tb: %6.2f%s/phút, Kích thước khối: %i Byte Khối hiện tại: %llu Khối tổng: %llu Kích thước thiết bị: %s = %llu Khối Äã được: %s Còn lại: %s Hê thống tập tin: %s Dung lượng còn trống: %s = %llu Khối Partclone đã kiểm tra ảnh (%s) thành công Partclone đã nhân bản thành công thiết bị (%s) vào thiết bị (%s) Partclone đã nhân bản thành công thiết bị (%s) thành ảnh (%s) Partclone đã ánh xạ thành công thiết bị (%s) vào nhật ký tên miá»n (%s) Partclone đã phục hồi thành công ảnh (%s) vào thiết bị (%s) Partclone phiên bản %s Tốc độ: %6.2f%s/phútDung lượng đã dùng: %s = %llu Khối Bắt đầu sao lưu dá»± phòng thiết bị (%s) vào thiết bị(%s) Äang kiểm tra ảnh (%s) Bắt đầu nhân bản thiết bị (%s) thành ảnh (%s) Bắt đầu ánh xạ thiết bị (%s) vào nhật ký tên miá»n (%s) Bắt đầu phục hồi ảnh (%s) vào thiết bị (%s) Thá»i gian tổng cá»™ng: %s Còn lại: %s partclone-0.2.86/po/vi.po000066400000000000000000000115021262102574200151720ustar00rootroot00000000000000# Vietnamese translation for partclone. # Copyright (C) 2013 thomas@nchc.org.tw # This file is distributed under the same license as the partclone package. # First translated by Trần Ngá»c Quân , 2013. # msgid "" msgstr "" "Project-Id-Version: partclone-0.2.61\n" "Report-Msgid-Bugs-To: thomas@nchc.org.tw\n" "POT-Creation-Date: 2015-09-24 10:11+0800\n" "PO-Revision-Date: 2013-06-13 09:03+0700\n" "Last-Translator: Trần Ngá»c Quân \n" "Language-Team: Vietnamese \n" "Language: vi\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 1.5.5\n" "X-Poedit-SourceCharset: UTF-8\n" #: src/progress.c:200 #, c-format msgid "\r%80c\rElapsed: %s, Remaining: %s, Completed: %6.2f%%" msgstr "\r%80c\rÄã được: %s, Còn: %s, Äã hoàn tất: %6.2f%%" #: src/progress.c:203 #, c-format msgid ", %6.2f%s/min," msgstr ", %6.2f%s/phút," #: src/progress.c:211 #, c-format msgid "\r%80c\rElapsed: %s, Remaining: %s, Completed: 100.00%%" msgstr "\r%80c\rÄã được: %s, Còn: %s, Äã hoàn tất: 100.00%%" #: src/progress.c:213 #, c-format msgid ", Rate: %6.2f%s/min," msgstr ", Tốc độ: %6.2f%s/phút, " #: src/progress.c:217 #, c-format msgid "" "\n" "Total Time: %s, " msgstr "" "\n" "Thá»i gian tổng cá»™ng: %s, " #: src/progress.c:219 #, c-format msgid "Ave. Rate: %6.1f%s/min, " msgstr "Tốc độ tb: %6.1f%s/phút, " #: src/progress.c:220 #, c-format msgid "%s" msgstr "%s" #: src/progress.c:247 #, c-format msgid "Elapsed: %s Remaining: %s " msgstr "Äã được: %s Còn lại: %s " #: src/progress.c:249 #, c-format msgid "Rate: %6.2f%s/min" msgstr "Tốc độ: %6.2f%s/phút" #: src/progress.c:251 #, c-format msgid "Current Block: %llu Total Block: %llu " msgstr "Khối hiện tại: %llu Khối tổng: %llu " #: src/progress.c:282 #, c-format msgid "Total Time: %s Remaining: %s " msgstr "Thá»i gian tổng cá»™ng: %s Còn lại: %s " #: src/progress.c:284 #, c-format msgid "Ave. Rate: %6.2f%s/min" msgstr "Tốc độ tb: %6.2f%s/phút, " #: src/partclone.c:1094 #, c-format msgid "Partclone v%s http://partclone.org\n" msgstr "Partclone phiên bản %s \n" #: src/partclone.c:1096 #, c-format msgid "Starting to check image (%s)\n" msgstr "Äang kiểm tra ảnh (%s)\n" #: src/partclone.c:1098 #, c-format msgid "Starting to clone device (%s) to image (%s)\n" msgstr "Bắt đầu nhân bản thiết bị (%s) thành ảnh (%s)\n" #: src/partclone.c:1100 #, c-format msgid "Starting to restore image (%s) to device (%s)\n" msgstr "Bắt đầu phục hồi ảnh (%s) vào thiết bị (%s)\n" #: src/partclone.c:1102 #, c-format msgid "Starting to back up device(%s) to device(%s)\n" msgstr "Bắt đầu sao lưu dá»± phòng thiết bị (%s) vào thiết bị(%s)\n" #: src/partclone.c:1104 #, c-format msgid "Starting to map device (%s) to domain log (%s)\n" msgstr "Bắt đầu ánh xạ thiết bị (%s) vào nhật ký tên miá»n (%s)\n" #: src/partclone.c:1106 #, fuzzy, c-format msgid "Starting to clone/restore (%s) to (%s) with dd mode\n" msgstr "Bắt đầu nhân bản thiết bị (%s) thành ảnh (%s)\n" #: src/partclone.c:1108 msgid "Display image information\n" msgstr "" #: src/partclone.c:1129 #, c-format msgid "File system: %s\n" msgstr "Hê thống tập tin: %s\n" #: src/partclone.c:1132 #, c-format msgid "Device size: %s = %llu Blocks\n" msgstr "Kích thước thiết bị: %s = %llu Khối\n" #: src/partclone.c:1135 #, c-format msgid "Space in use: %s = %llu Blocks\n" msgstr "Dung lượng đã dùng: %s = %llu Khối\n" #: src/partclone.c:1138 #, c-format msgid "Free Space: %s = %llu Blocks\n" msgstr "Dung lượng còn trống: %s = %llu Khối\n" #: src/partclone.c:1140 #, c-format msgid "Block size: %i Byte\n" msgstr "Kích thước khối: %i Byte\n" #: src/partclone.c:1152 #, c-format msgid "Partclone successfully checked the image (%s)\n" msgstr "Partclone đã kiểm tra ảnh (%s) thành công\n" #: src/partclone.c:1154 #, c-format msgid "Partclone successfully cloned the device (%s) to the image (%s)\n" msgstr "Partclone đã nhân bản thành công thiết bị (%s) thành ảnh (%s)\n" #: src/partclone.c:1156 #, c-format msgid "Partclone successfully restored the image (%s) to the device (%s)\n" msgstr "Partclone đã phục hồi thành công ảnh (%s) vào thiết bị (%s)\n" #: src/partclone.c:1158 #, c-format msgid "Partclone successfully cloned the device (%s) to the device (%s)\n" msgstr "Partclone đã nhân bản thành công thiết bị (%s) vào thiết bị (%s)\n" #: src/partclone.c:1160 #, c-format msgid "Partclone successfully mapped the device (%s) to the domain log (%s)\n" msgstr "" "Partclone đã ánh xạ thành công thiết bị (%s) vào nhật ký tên miá»n (%s)\n" partclone-0.2.86/po/zh_CN.gmo000066400000000000000000000047221262102574200157270ustar00rootroot00000000000000Þ•Ü%œ014C5x®±ÀÕî7.IAx@ºEûBA„-–Ä,â/.?nKŒØ1í2RUd{˜³Íèú**?9j*¤Ï)ä )' 2Q )„ #®     Total Time: %s, %80c Elapsed: %s, Remaining: %s, Completed: %6.2f%% %80c Elapsed: %s, Remaining: %s, Completed: 100.00%%%s, %6.2f%s/min,, Rate: %6.2f%s/min,Ave. Rate: %6.1f%s/min, Ave. Rate: %6.2f%s/minBlock size: %i Byte Elapsed: %s Remaining: %s File system: %s Partclone successfully checked the image (%s) Partclone successfully cloned the device (%s) to the device (%s) Partclone successfully cloned the device (%s) to the image (%s) Partclone successfully mapped the device (%s) to the domain log (%s) Partclone successfully restored the image (%s) to the device (%s) Rate: %6.2f%s/minStarting to back up device(%s) to device(%s) Starting to check image (%s) Starting to clone device (%s) to image (%s) Starting to map device (%s) to domain log (%s) Starting to restore image (%s) to device (%s) Total Time: %s Remaining: %s Project-Id-Version: Partclone 0.2.51 Report-Msgid-Bugs-To: thomas@nchc.org.tw POT-Creation-Date: 2015-09-24 10:11+0800 PO-Revision-Date: 2007-11-01 11:35+0800 Last-Translator: Peter Dave Hello Language-Team: Peter Dave Hello Language: zh_CN MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 全部时间:%s, %80c ç»è¿‡ï¼š%s, 剩余: %s, 完æˆï¼š%6.2f%% %80c ç»è¿‡ï¼š%s, 剩余: %s, 完æˆï¼š100.00%%%s, %6.2f%s/min,, 速率:%6.2f%s/minå¹³å‡é€ŸçŽ‡ï¼š%6.1f%s/min, å¹³å‡é€ŸçŽ‡ï¼š%6.2f%s/min装置å—大å°: %i Byte ç»è¿‡ï¼š%s 剩余: %s 文件系统: %s æ£€æŸ¥é•œåƒ (%s) å®Œæˆ å¤‡ä»½ 装置 (%s) 到 装置 (%s) å®Œæˆ å¤‡ä»½ 装置 (%s) 到 é•œåƒ (%s) å®Œæˆ è¾“å‡ºè£…ç½® (%s) å—ä¿¡æ¯ åˆ° æ•°æ®æ–‡ä»¶ (%s) å®Œæˆ æ¢å¤ é•œåƒ (%s) 到 装置 (%s) å®Œæˆ é€ŸçŽ‡ï¼š%6.2f%s/min开始备份 装置 (%s) 到 装置 (%s) å¼€å§‹æ£€æŸ¥é•œåƒ (%s) 开始备份 装置 (%s) 到 é•œåƒ (%s) 开始输出 装置 (%s)å— åˆ° 资料文件 (%s) 开始æ¢å¤ é•œåƒ (%s) 到 装置 (%s) 全部时间:%s 剩余时间: %s partclone-0.2.86/po/zh_CN.po000066400000000000000000000102361262102574200155600ustar00rootroot00000000000000# Simplified Chinese translations for Partclone package. # This file is distributed under the same license as the Partclone package. # msgid "" msgstr "" "Project-Id-Version: Partclone 0.2.51\n" "Report-Msgid-Bugs-To: thomas@nchc.org.tw\n" "POT-Creation-Date: 2015-09-24 10:11+0800\n" "PO-Revision-Date: 2007-11-01 11:35+0800\n" "Last-Translator: Peter Dave Hello\n" "Language-Team: Peter Dave Hello\n" "Language: zh_CN\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: src/progress.c:200 #, c-format msgid "\r%80c\rElapsed: %s, Remaining: %s, Completed: %6.2f%%" msgstr "\r%80c\rç»è¿‡ï¼š%s, 剩余: %s, 完æˆï¼š%6.2f%%" #: src/progress.c:203 #, c-format msgid ", %6.2f%s/min," msgstr ", %6.2f%s/min," #: src/progress.c:211 #, c-format msgid "\r%80c\rElapsed: %s, Remaining: %s, Completed: 100.00%%" msgstr "\r%80c\rç»è¿‡ï¼š%s, 剩余: %s, 完æˆï¼š100.00%%" #: src/progress.c:213 #, c-format msgid ", Rate: %6.2f%s/min," msgstr ", 速率:%6.2f%s/min" #: src/progress.c:217 #, c-format msgid "" "\n" "Total Time: %s, " msgstr "" "\n" "全部时间:%s, " #: src/progress.c:219 #, c-format msgid "Ave. Rate: %6.1f%s/min, " msgstr "å¹³å‡é€ŸçŽ‡ï¼š%6.1f%s/min, " #: src/progress.c:220 #, c-format msgid "%s" msgstr "%s" #: src/progress.c:247 #, c-format msgid "Elapsed: %s Remaining: %s " msgstr "ç»è¿‡ï¼š%s 剩余: %s " #: src/progress.c:249 #, c-format msgid "Rate: %6.2f%s/min" msgstr "速率:%6.2f%s/min" #: src/progress.c:251 #, fuzzy, c-format msgid "Current Block: %llu Total Block: %llu " msgstr "ç›®å‰å—: %lld å…¨éƒ¨å— %lld " #: src/progress.c:282 #, c-format msgid "Total Time: %s Remaining: %s " msgstr "全部时间:%s 剩余时间: %s " #: src/progress.c:284 #, c-format msgid "Ave. Rate: %6.2f%s/min" msgstr "å¹³å‡é€ŸçŽ‡ï¼š%6.2f%s/min" #: src/partclone.c:1094 #, c-format msgid "Partclone v%s http://partclone.org\n" msgstr "" #: src/partclone.c:1096 #, c-format msgid "Starting to check image (%s)\n" msgstr "å¼€å§‹æ£€æŸ¥é•œåƒ (%s)\n" #: src/partclone.c:1098 #, c-format msgid "Starting to clone device (%s) to image (%s)\n" msgstr "开始备份 装置 (%s) 到 é•œåƒ (%s)\n" #: src/partclone.c:1100 #, c-format msgid "Starting to restore image (%s) to device (%s)\n" msgstr "开始æ¢å¤ é•œåƒ (%s) 到 装置 (%s)\n" #: src/partclone.c:1102 #, c-format msgid "Starting to back up device(%s) to device(%s)\n" msgstr "开始备份 装置 (%s) 到 装置 (%s)\n" #: src/partclone.c:1104 #, c-format msgid "Starting to map device (%s) to domain log (%s)\n" msgstr "开始输出 装置 (%s)å— åˆ° 资料文件 (%s)\n" #: src/partclone.c:1106 #, fuzzy, c-format msgid "Starting to clone/restore (%s) to (%s) with dd mode\n" msgstr "开始备份 装置 (%s) 到 é•œåƒ (%s)\n" #: src/partclone.c:1108 msgid "Display image information\n" msgstr "" #: src/partclone.c:1129 #, c-format msgid "File system: %s\n" msgstr "文件系统: %s\n" #: src/partclone.c:1132 #, fuzzy, c-format msgid "Device size: %s = %llu Blocks\n" msgstr "装置大å°: %s = %lld Blocks\n" #: src/partclone.c:1135 #, fuzzy, c-format msgid "Space in use: %s = %llu Blocks\n" msgstr "装置使用到空间: %s = %lld Blocks\n" #: src/partclone.c:1138 #, fuzzy, c-format msgid "Free Space: %s = %llu Blocks\n" msgstr "剩余空间: %s = %lld Blocks\n" #: src/partclone.c:1140 #, c-format msgid "Block size: %i Byte\n" msgstr "装置å—大å°: %i Byte\n" #: src/partclone.c:1152 #, c-format msgid "Partclone successfully checked the image (%s)\n" msgstr "æ£€æŸ¥é•œåƒ (%s) 完æˆ\n" #: src/partclone.c:1154 #, c-format msgid "Partclone successfully cloned the device (%s) to the image (%s)\n" msgstr "备份 装置 (%s) 到 é•œåƒ (%s) 完æˆ\n" #: src/partclone.c:1156 #, c-format msgid "Partclone successfully restored the image (%s) to the device (%s)\n" msgstr "æ¢å¤ é•œåƒ (%s) 到 装置 (%s) 完æˆ\n" #: src/partclone.c:1158 #, c-format msgid "Partclone successfully cloned the device (%s) to the device (%s)\n" msgstr "备份 装置 (%s) 到 装置 (%s) 完æˆ\n" #: src/partclone.c:1160 #, c-format msgid "Partclone successfully mapped the device (%s) to the domain log (%s)\n" msgstr "输出装置 (%s) å—ä¿¡æ¯ åˆ° æ•°æ®æ–‡ä»¶ (%s) 完æˆ\n" partclone-0.2.86/po/zh_TW.gmo000066400000000000000000000050241262102574200157550ustar00rootroot00000000000000Þ•Ü%œ014C5x®±ÀÕî7.IAx@ºEûBA„-–Ä,â/.?nxŒ12L‚‘¨Åàý**G-r9 -Ú ) G ,c 2 ,à #ð     Total Time: %s, %80c Elapsed: %s, Remaining: %s, Completed: %6.2f%% %80c Elapsed: %s, Remaining: %s, Completed: 100.00%%%s, %6.2f%s/min,, Rate: %6.2f%s/min,Ave. Rate: %6.1f%s/min, Ave. Rate: %6.2f%s/minBlock size: %i Byte Elapsed: %s Remaining: %s File system: %s Partclone successfully checked the image (%s) Partclone successfully cloned the device (%s) to the device (%s) Partclone successfully cloned the device (%s) to the image (%s) Partclone successfully mapped the device (%s) to the domain log (%s) Partclone successfully restored the image (%s) to the device (%s) Rate: %6.2f%s/minStarting to back up device(%s) to device(%s) Starting to check image (%s) Starting to clone device (%s) to image (%s) Starting to map device (%s) to domain log (%s) Starting to restore image (%s) to device (%s) Total Time: %s Remaining: %s Project-Id-Version: Partclone 0.2.51 Report-Msgid-Bugs-To: thomas@nchc.org.tw POT-Creation-Date: 2015-09-24 10:11+0800 PO-Revision-Date: 2007-11-01 11:35+0800 Last-Translator: Yu-Chin Tsai Language-Team: Chinese (traditional) Language: zh_TW MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 全部時間:%s, %80c ç¶“éŽï¼š%s, 剩餘: %s, 完æˆï¼š%6.2f%% %80c ç¶“éŽï¼š%s, 剩餘: %s, 完æˆï¼š100.00%%%s, %6.2f%s/min,, 速率:%6.2f%s/minå¹³å‡é€ŸçŽ‡ï¼š%6.1f%s/min, å¹³å‡é€ŸçŽ‡ï¼š%6.2f%s/minè£ç½®å€å¡Šå¤§å°: %i Byte ç¶“éŽï¼š%s 剩餘: %s 檔案系統: %s 檢查å°è±¡æª” (%s) å®Œæˆ å‚™ä»½ è£ç½® (%s) 到 è£ç½® (%s) å®Œæˆ å‚™ä»½ è£ç½® (%s) 到 å°è±¡æª” (%s) å®Œæˆ è¼¸å‡ºè£ç½® (%s) å€å¡Šè³‡è¨Š 到 資料檔 (%s) å®Œæˆ é‚„åŽŸ å°è±¡æª” (%s) 到 è£ç½® (%s) å®Œæˆ é€ŸçŽ‡ï¼š%6.2f%s/min開始備份 è£ç½® (%s) 到 è£ç½® (%s) 開始檢查å°è±¡æª” (%s) 開始備份 è£ç½® (%s) 到 å°è±¡æª” (%s) 開始輸出 è£ç½® (%s)å€å¡Š 到 資料檔 (%s) 開始還原 å°è±¡æª” (%s) 到 è£ç½® (%s) 全部時間:%s 剩餘時間: %s partclone-0.2.86/po/zh_TW.po000066400000000000000000000104611262102574200156120ustar00rootroot00000000000000# Chinese translations for Partclone package. # Copyright (C) 2007 thomas@nchc.org.tw # This file is distributed under the same license as the Partclone package. # Yu-Chin Tsai , 2007. # msgid "" msgstr "" "Project-Id-Version: Partclone 0.2.51\n" "Report-Msgid-Bugs-To: thomas@nchc.org.tw\n" "POT-Creation-Date: 2015-09-24 10:11+0800\n" "PO-Revision-Date: 2007-11-01 11:35+0800\n" "Last-Translator: Yu-Chin Tsai \n" "Language-Team: Chinese (traditional) \n" "Language: zh_TW\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: src/progress.c:200 #, c-format msgid "\r%80c\rElapsed: %s, Remaining: %s, Completed: %6.2f%%" msgstr "\r%80c\rç¶“éŽï¼š%s, 剩餘: %s, 完æˆï¼š%6.2f%%" #: src/progress.c:203 #, c-format msgid ", %6.2f%s/min," msgstr ", %6.2f%s/min," #: src/progress.c:211 #, c-format msgid "\r%80c\rElapsed: %s, Remaining: %s, Completed: 100.00%%" msgstr "\r%80c\rç¶“éŽï¼š%s, 剩餘: %s, 完æˆï¼š100.00%%" #: src/progress.c:213 #, c-format msgid ", Rate: %6.2f%s/min," msgstr ", 速率:%6.2f%s/min" #: src/progress.c:217 #, c-format msgid "" "\n" "Total Time: %s, " msgstr "" "\n" "全部時間:%s, " #: src/progress.c:219 #, c-format msgid "Ave. Rate: %6.1f%s/min, " msgstr "å¹³å‡é€ŸçŽ‡ï¼š%6.1f%s/min, " #: src/progress.c:220 #, c-format msgid "%s" msgstr "%s" #: src/progress.c:247 #, c-format msgid "Elapsed: %s Remaining: %s " msgstr "ç¶“éŽï¼š%s 剩餘: %s " #: src/progress.c:249 #, c-format msgid "Rate: %6.2f%s/min" msgstr "速率:%6.2f%s/min" #: src/progress.c:251 #, fuzzy, c-format msgid "Current Block: %llu Total Block: %llu " msgstr "ç›®å‰å€å¡Š: %lld 全部å€å¡Š %lld " #: src/progress.c:282 #, c-format msgid "Total Time: %s Remaining: %s " msgstr "全部時間:%s 剩餘時間: %s " #: src/progress.c:284 #, c-format msgid "Ave. Rate: %6.2f%s/min" msgstr "å¹³å‡é€ŸçŽ‡ï¼š%6.2f%s/min" #: src/partclone.c:1094 #, c-format msgid "Partclone v%s http://partclone.org\n" msgstr "" #: src/partclone.c:1096 #, c-format msgid "Starting to check image (%s)\n" msgstr "開始檢查å°è±¡æª” (%s)\n" #: src/partclone.c:1098 #, c-format msgid "Starting to clone device (%s) to image (%s)\n" msgstr "開始備份 è£ç½® (%s) 到 å°è±¡æª” (%s)\n" #: src/partclone.c:1100 #, c-format msgid "Starting to restore image (%s) to device (%s)\n" msgstr "開始還原 å°è±¡æª” (%s) 到 è£ç½® (%s)\n" #: src/partclone.c:1102 #, c-format msgid "Starting to back up device(%s) to device(%s)\n" msgstr "開始備份 è£ç½® (%s) 到 è£ç½® (%s)\n" #: src/partclone.c:1104 #, c-format msgid "Starting to map device (%s) to domain log (%s)\n" msgstr "開始輸出 è£ç½® (%s)å€å¡Š 到 資料檔 (%s)\n" #: src/partclone.c:1106 #, fuzzy, c-format msgid "Starting to clone/restore (%s) to (%s) with dd mode\n" msgstr "開始備份 è£ç½® (%s) 到 å°è±¡æª” (%s)\n" #: src/partclone.c:1108 msgid "Display image information\n" msgstr "" #: src/partclone.c:1129 #, c-format msgid "File system: %s\n" msgstr "檔案系統: %s\n" #: src/partclone.c:1132 #, fuzzy, c-format msgid "Device size: %s = %llu Blocks\n" msgstr "è£ç½®å¤§å°: %s = %lld Blocks\n" #: src/partclone.c:1135 #, fuzzy, c-format msgid "Space in use: %s = %llu Blocks\n" msgstr "è£ç½®ä½¿ç”¨åˆ°ç©ºé–“: %s = %lld Blocks\n" #: src/partclone.c:1138 #, fuzzy, c-format msgid "Free Space: %s = %llu Blocks\n" msgstr "剩餘空間: %s = %lld Blocks\n" #: src/partclone.c:1140 #, c-format msgid "Block size: %i Byte\n" msgstr "è£ç½®å€å¡Šå¤§å°: %i Byte\n" #: src/partclone.c:1152 #, c-format msgid "Partclone successfully checked the image (%s)\n" msgstr "檢查å°è±¡æª” (%s) 完æˆ\n" #: src/partclone.c:1154 #, c-format msgid "Partclone successfully cloned the device (%s) to the image (%s)\n" msgstr "備份 è£ç½® (%s) 到 å°è±¡æª” (%s) 完æˆ\n" #: src/partclone.c:1156 #, c-format msgid "Partclone successfully restored the image (%s) to the device (%s)\n" msgstr "還原 å°è±¡æª” (%s) 到 è£ç½® (%s) 完æˆ\n" #: src/partclone.c:1158 #, c-format msgid "Partclone successfully cloned the device (%s) to the device (%s)\n" msgstr "備份 è£ç½® (%s) 到 è£ç½® (%s) 完æˆ\n" #: src/partclone.c:1160 #, c-format msgid "Partclone successfully mapped the device (%s) to the domain log (%s)\n" msgstr "輸出è£ç½® (%s) å€å¡Šè³‡è¨Š 到 資料檔 (%s) 完æˆ\n" partclone-0.2.86/release.sh000077500000000000000000000136711262102574200155660ustar00rootroot00000000000000#!/bin/bash set -e packbase="$HOME/download/pre-release/" [ ! -d $presrc ] && mkdir $presrc rm -rf $packbase/* presrc="$HOME/download/pre-release/src" ptlpath="$HOME/partclone" [ ! -d $presrc ] && mkdir $presrc GPGID="0x68cdf01d" SRC=0 DPKG=0 TAGS=0 PO=0 LOG=0 SYNC=0 VER=0 VERSION=auto gVERSION="HEAD" TEST=0 _dch_options="-b" is_release=1 USAGE(){ cat << EOF $0 is script to auto release partclone. This cript will create partclone tar ball file and auto build debian package with my key. It's only for developer used. recognized flags are: -s, --src build tar ball -d, --dpkg build dpkg files -p, --po run make po -t, --test run make check -v, --ver update version.h -l, --sync-log update Changelog -f, --sync-fs update source i.e btrfs -g, --git give git commit version like b655 or 0.2.54 -a, --tags add version as git tag -n, --no_push do NOT auto push to git repo -h, --help show this help EOF } check_option(){ while [ $# -gt 0 ]; do case "$1" in -g|--git) shift if [ -z "$(echo $1 |grep ^-.)" ]; then gVERSION=$1 shift pushd $ptlpath #git pull vgit=$(git log -1 $gVERSION) if [ -z "$vgit" ]; then echo "can't find git version $VERSION"> 2& exit 1 fi popd fi ;; -d|--dpkg) DPKG=1 shift ;; -s|--src) SRC=1 shift ;; -t|--test) TEST=1 shift ;; -a|--tags) TAGS=1 shift ;; -p|--po) PO=1 shift ;; -l|--sync-log) LOG=1 shift ;; -f|--sync-fs) SYNC=1 shift ;; -n|--no_push) is_release=0 shift ;; -v|--ver) VER=1 shift ;; -h|--help) USAGE >& 2 exit 2 ;; -*) echo "${0}: ${1}: invalid option" >&2 USAGE >& 2 exit 2 ;; *) break ;; esac done } # exit if not git is_git(){ GIT_REPOSITORY=`git remote -v | grep partclone` if [ "${GIT_REPOSITORY}" = "" ]; then echo "not git repository?" exit 0 fi } check_version(){ pushd $ptlpath is_git #git pull git fetch --tags if [ "$gVERSION" != "HEAD" ]; then git checkout $gVERSION -b 'g_$gVERSION' ptlversion=$(grep ^PACKAGE_VERSION= configure | sed s/PACKAGE_VERSION//g | sed s/[\'=]//g) if [ "$gVERSION" == "$ptlversion" ]; then VERSION=$ptlversion _dch_options="-v $VERSION-2 -b" else VERSION=$ptlversion~git$gVERSION _dch_options="-v $VERSION-1 -b" fi fi if [ "$VERSION" == "auto" ];then VERSION=$(grep ^PACKAGE_VERSION= configure | sed s/PACKAGE_VERSION//g | sed s/[\'=]//g) gVERSION="HEAD" _dch_options=" -v $VERSION-1 -b" fi popd if [ -z "$VERSION" ]; then echo "can't find version $VERSION"> 2& exit 1 fi } tarball (){ pushd $ptlpath ## release tar ball autoreconf update_version update_po sync_log git add -u git commit -m "release $VERSION" git archive --format=tar --prefix=partclone-$VERSION/ $gVERSION | gzip > $presrc/partclone-$VERSION.tar.gz git archive --format=tar --prefix=partclone-$VERSION/ $gVERSION | gzip > $presrc/partclone_$VERSION.orig.tar.gz [ is_releae == 1 ] && git push popd } dpkg_package() { pushd $packbase if [ -f $presrc/partclone_$VERSION.orig.tar.gz ]; then cp $presrc/partclone_$VERSION.orig.tar.gz $packbase/ && tar -zxvf partclone_$VERSION.orig.tar.gz else echo "copy partclone_$VERSION.orig.tar.gz to $presrc/partclone_$VERSION.orig.tar.gz first" echo "i.e: wget http://partclone.nchc.org.tw/download/source/partclone_$VERSION.orig.tar.gz -P $presrc/" exit fi pushd partclone-$VERSION cp -r README.Packages/debian debian debuild -k$GPGID popd popd } push_tags(){ pushd $ptlpath git tag -f -a $VERSION -m "release $VERSION" git push --tags popd } sync_log(){ pushd $ptlpath is_git # get source code from Jim Meyering at # http://git.mymadcat.com/index.php/p/tracker/source/tree/master/gitlog-to-changelog perl gitlog-to-changelog --since 1999-01-01 > ChangeLog popd cp -r README.Packages/debian debian dch $_dch_options dch -r cp -r debian README.Packages/ } update_po(){ pushd $ptlpath make -C po/ update-po popd } sync_fs(){ BTRFS_SOURCE="bitops.h ctree.h extent_io.c inode-item.c math.h radix-tree.c root-tree.c ulist.c volumes.c btrfsck.h dir-item.c extent_io.h inode-map.c print-tree.c radix-tree.h send.h ulist.h volumes.h btrfs-list.c disk-io.c extent-tree.c ioctl.h print-tree.h raid6.c send-stream.c utils.c btrfs-list.h disk-io.h file-item.c kerncompat.h qgroup.c rbtree.c send-stream.h utils.h crc32c.c free-space-cache.c list.h qgroup.h rbtree.h send-utils.c utils-lib.c rbtree-utils.c crc32c.h extent-cache.c free-space-cache.h list_sort.c qgroup-verify.c repair.c send-utils.h uuid-tree.c ctree.c extent-cache.h hash.h list_sort.h qgroup-verify.h repair.h transaction.h version.h rbtree-utils.h rbtree_augmented.h" echo "manual run : cp $BTRFS_SOURCE $ptlpath/src/btrfs/" } update_version(){ pushd $ptlpath file="$ptlpath/src/version.h" is_git GIT_REVISION=`git log -1 | grep ^commit | sed 's/commit //'` #GIT_REVISION_UPSTREAM=`git log master -1 | grep commit | sed 's/commit //'` git_ver="none" #if [ "${GIT_REVISION_UPSTREAM}" != "" ]; then # git_ver=$GIT_REVISION_UPSTREAM #el if [ "${GIT_REVISION}" != "" ]; then git_ver=$GIT_REVISION else git_ver="none" fi if [ "$git_ver" != "none" ]; then echo "create ${file}" cat > ${file} << EOF /* DO NOT EDIT THIS FILE - IT IS REGENERATED AT EVERY COMPILE - * IT GIVES BETTER TRACKING OF DEVELOPMENT VERSIONS * WHETHER THEY ARE BUILT BY OTHERS OR DURING DEVELOPMENT OR FOR THE * OFFICIAL PARTCLONE RELEASES. */ #define git_version "$git_ver" EOF fi } # main check_option "$@" check_version [ $SRC == 1 ] && tarball [ $DPKG == 1 ] && dpkg_package [ $LOG == 1 ] && sync_log [ $TAGS == 1 ] && push_tags [ $PO == 1 ] && update_po [ $SYNC == 1 ] && sync_fs [ $VER == 1 ] && update_version partclone-0.2.86/src/000077500000000000000000000000001262102574200143665ustar00rootroot00000000000000partclone-0.2.86/src/Makefile.am000066400000000000000000000236061262102574200164310ustar00rootroot00000000000000AUTOMAKE_OPTIONS = subdir-objects AM_CPPFLAGS = -DLOCALEDIR=\"$(localedir)\" -D_FILE_OFFSET_BITS=64 LDADD = $(LIBINTL) sbin_PROGRAMS=partclone.info partclone.dd partclone.restore partclone.chkimg partclone.imager TOOLBOX = srcdir=$(top_srcdir) builddir=$(top_builddir) $(top_srcdir)/toolbox BTRFS_SOURCE=\ btrfs/bitops.h btrfs/ctree.h btrfs/extent_io.c btrfs/inode-item.c btrfs/math.h btrfs/radix-tree.c btrfs/root-tree.c btrfs/ulist.c btrfs/volumes.c\ btrfs/btrfsck.h btrfs/dir-item.c btrfs/extent_io.h btrfs/inode-map.c btrfs/print-tree.c btrfs/radix-tree.h btrfs/send.h btrfs/ulist.h btrfs/volumes.h\ btrfs/btrfs-list.c btrfs/disk-io.c btrfs/extent-tree.c btrfs/ioctl.h btrfs/print-tree.h btrfs/raid6.c btrfs/send-stream.c btrfs/utils.c\ btrfs/btrfs-list.h btrfs/disk-io.h btrfs/file-item.c btrfs/kerncompat.h btrfs/qgroup.c btrfs/rbtree.c btrfs/send-stream.h btrfs/utils.h\ btrfs/crc32c.c btrfs/free-space-cache.c btrfs/list.h btrfs/qgroup.h btrfs/rbtree.h btrfs/send-utils.c btrfs/utils-lib.c btrfs/rbtree-utils.c\ btrfs/crc32c.h btrfs/extent-cache.c btrfs/free-space-cache.h btrfs/list_sort.c btrfs/qgroup-verify.c btrfs/repair.c btrfs/send-utils.h\ btrfs/uuid-tree.c btrfs/ctree.c btrfs/extent-cache.h btrfs/hash.h btrfs/list_sort.h btrfs/qgroup-verify.h btrfs/repair.h btrfs/transaction.h\ btrfs/version.h btrfs/rbtree-utils.h btrfs/rbtree_augmented.h XFS_SOURCE=\ xfs/atomic.h xfs/libxfs_priv.h xfs/xfs_arch.h xfs/xfs_da_format.h xfs/xfs_inode_fork.h xfs/bitops.h xfs/libxlog.h xfs/xfs_attr.c xfs/xfs_dir2_block.c xfs/xfs_inode.h xfs/cache.c xfs/linux.c xfs/xfs_attr_leaf.c xfs/xfs_dir2.c xfs/xfs_log_format.h xfs/cache.h xfs/linux.h xfs/xfs_attr_leaf.h xfs/xfs_dir2_data.c xfs/xfs_log_recover.h xfs/command.h xfs/list.h xfs/xfs_attr_remote.c xfs/xfs_dir2.h xfs/xfs_log_rlimit.c xfs/crc32.c xfs/logitem.c xfs/xfs_attr_remote.h xfs/xfs_dir2_leaf.c xfs/xfs_metadump.h xfs/crc32defs.h xfs/parent.h xfs/xfs_attr_sf.h xfs/xfs_dir2_node.c xfs/xfs_mount.h xfs/path.h xfs/xfs_bit.c xfs/xfs_dir2_priv.h xfs/xfs_quota_defs.h xfs/platform_defs.h xfs/xfs_bit.h xfs/xfs_dir2_sf.c xfs/xfs_rtbitmap.c xfs/handle.h xfs/platform_defs.h.in xfs/xfs_bmap_btree.c xfs/xfs_dquot_buf.c xfs/xfs_sb.c xfs/hlist.h xfs/project.h xfs/xfs_bmap_btree.h xfs/xfs_format.h xfs/xfs_sb.h xfs/init.c xfs/radix-tree.c xfs/xfs_bmap.c xfs/xfs_fs.h xfs/xfs_shared.h xfs/init.h xfs/radix-tree.h xfs/xfs_bmap.h xfs/xfs.h xfs/xfs_symlink_remote.c xfs/input.h xfs/rdwr.c xfs/xfs_btree.c xfs/xfs_ialloc_btree.c xfs/xfs_trace.h xfs/jdm.h xfs/trans.c xfs/xfs_btree.h xfs/xfs_ialloc_btree.h xfs/xfs_trans.h xfs/kmem.c xfs/util.c xfs/xfs_btree_trace.h xfs/xfs_ialloc.c xfs/xfs_trans_resv.c xfs/kmem.h xfs/xfs_alloc_btree.c xfs/xfs_cksum.h xfs/xfs_ialloc.h xfs/xfs_trans_resv.h xfs/libxfs_api_defs.h xfs/xfs_alloc_btree.h xfs/xfs_da_btree.c xfs/xfs_inode_buf.c xfs/xfs_trans_space.h xfs/libxfs.h xfs/xfs_alloc.c xfs/xfs_da_btree.h xfs/xfs_inode_buf.h xfs/xfs_types.h xfs/libxfs_io.h xfs/xfs_alloc.h xfs/xfs_da_format.c xfs/xfs_inode_fork.c xfs/xqm.h xfs/crc32table.h EXFATFS_SOURCE=exfat/cluster.c exfat/utf.c exfat/utils.c exfat/lookup.c exfat/io.c exfat/log.c exfat/node.c exfat/mount.c exfat/time.c F2FS_SOURCE=f2fs/fsck.c f2fs/libf2fs.c f2fs/fsck.h f2fs/mount.c f2fs/f2fs_fs.h f2fs/list.h f2fs/f2fs.h if ENABLE_STATIC AM_LDFLAGS=-static endif if ENABLE_TINFO LIBS+=-ltinfo endif AM_CFLAGS=-D_FILE_OFFSET_BITS=64 if ENABLE_MEMTRACE AM_CFLAGS+=-DMEMTRACE -DMEMWATCH -DMW_STDIO endif if ENABLE_NCURSESW AM_CFLAGS+=-I/usr/include/ncursesw endif version.h: FORCE $(TOOLBOX) --update-version partclone_info_SOURCES=info.c partclone.c partclone.h fs_common.h partclone_restore_SOURCES=main.c partclone.c progress.c ddclone.c ddclone.h partclone.h progress.h gettext.h partclone_restore_CFLAGS=-DRESTORE -DDD partclone_chkimg_SOURCES=main.c partclone.c progress.c ddclone.c ddclone.h partclone.h progress.h gettext.h partclone_chkimg_CFLAGS=-DCHKIMG -DDD partclone_dd_SOURCES=main.c partclone.c progress.c ddclone.c ddclone.h partclone.h progress.h gettext.h partclone_dd_CFLAGS=-DDD partclone_imager_SOURCES=main.c partclone.c progress.c ddclone.c ddclone.h partclone.h progress.h gettext.h partclone_imager_CFLAGS=-DIMG if ENABLE_EXTFS sbin_PROGRAMS += partclone.extfs partclone_extfs_SOURCES=main.c partclone.c progress.c extfsclone.c extfsclone.h partclone.h progress.h gettext.h partclone_extfs_CFLAGS=-DEXTFS partclone_extfs_LDADD=-lext2fs -lcom_err -lpthread endif if ENABLE_REISERFS sbin_PROGRAMS += partclone.reiserfs partclone_reiserfs_SOURCES=main.c partclone.c progress.c reiserfsclone.c reiserfsclone.h partclone.h progress.h gettext.h partclone_reiserfs_CFLAGS=-DREISERFS partclone_reiserfs_LDADD=-lreiserfs -ldal endif if ENABLE_REISER4 sbin_PROGRAMS += partclone.reiser4 partclone_reiser4_SOURCES=main.c partclone.c progress.c reiser4clone.c reiser4clone.h partclone.h progress.h gettext.h partclone_reiser4_CFLAGS=-DREISER4 partclone_reiser4_LDADD=-lreiser4 -laal endif if ENABLE_HFSP sbin_PROGRAMS += partclone.hfsp partclone_hfsp_SOURCES=main.c partclone.c progress.c hfsplusclone.c hfsplusclone.h partclone.h progress.h gettext.h partclone_hfsp_CFLAGS=-DHFSPLUS endif if ENABLE_XFS sbin_PROGRAMS += partclone.xfs partclone_xfs_SOURCES=main.c partclone.c progress.c xfsclone.c xfsclone.h partclone.h progress.h gettext.h $(XFS_SOURCE) partclone_xfs_CFLAGS=-DXFS -D_GNU_SOURCE -DNDEBUG $(UUID_CFLAGS) partclone_xfs_LDADD=-lrt -lpthread -luuid endif if ENABLE_EXFAT sbin_PROGRAMS += partclone.exfat partclone_exfat_SOURCES=main.c partclone.c progress.c exfatclone.c exfatclone.h partclone.h progress.h gettext.h $(EXFATFS_SOURCE) partclone_exfat_CFLAGS=-DEXFAT -D_GNU_SOURCE -std=c99 endif if ENABLE_F2FS sbin_PROGRAMS += partclone.f2fs partclone_f2fs_SOURCES=main.c partclone.c progress.c f2fsclone.c f2fsclone.h partclone.h progress.h gettext.h $(F2FS_SOURCE) partclone_f2fs_CFLAGS=-DF2FS partclone_f2fs_LDADD=-luuid endif if ENABLE_NILFS2 sbin_PROGRAMS += partclone.nilfs2 partclone_nilfs2_SOURCES=main.c partclone.c progress.c nilfsclone.c nilfsclone.h partclone.h progress.h gettext.h partclone_nilfs2_CFLAGS=-DNILFS partclone_nilfs2_LDADD=-lnilfs endif if ENABLE_FAT sbin_PROGRAMS += partclone.fat partclone_fat_SOURCES=main.c partclone.c progress.c fatclone.c fatclone.h partclone.h progress.h gettext.h partclone_fat_CFLAGS=-DFAT endif sbin_PROGRAMS += partclone.ntfsfixboot partclone_ntfsfixboot_SOURCES=ntfsfixboot.c if ENABLE_NTFS sbin_PROGRAMS += partclone.ntfs partclone_ntfs_SOURCES=main.c partclone.c progress.c ntfsclone-ng.c ntfsclone-ng.h partclone.h progress.h gettext.h if ENABLE_NTFS_3G partclone_ntfs_CFLAGS=-DNTFS3G partclone_ntfs_LDADD=-lntfs-3g else partclone_ntfs_CFLAGS=-DNTFS partclone_ntfs_LDADD=-lntfs endif endif if ENABLE_UFS sbin_PROGRAMS += partclone.ufs partclone_ufs_SOURCES=main.c partclone.c progress.c ufsclone.c ufsclone.h partclone.h progress.h gettext.h partclone_ufs_CFLAGS=-DUFS -D_GNU_SOURCE partclone_ufs_LDADD=-lufs -lbsd endif if ENABLE_VMFS sbin_PROGRAMS += partclone.vmfs partclone_vmfs_SOURCES=main.c partclone.c progress.c vmfsclone.c vmfsclone.h partclone.h progress.h gettext.h partclone_vmfs_CFLAGS=-DVMFS -D_GNU_SOURCE $(UUID_CFLAGS) partclone_vmfs_LDADD=-lvmfs -luuid sbin_PROGRAMS += partclone.vmfs5 partclone_vmfs5_SOURCES=main.c partclone.c progress.c vmfs5clone.c vmfsclone.h partclone.h progress.h gettext.h partclone_vmfs5_CFLAGS=-DVMFS -D_GNU_SOURCE $(UUID_CFLAGS) partclone_vmfs5_LDADD=-lvmfs -luuid sbin_PROGRAMS += partclone.fstype partclone_fstype_SOURCES=fstype.c partclone_fstype_CFLAGS=-DVMFS -D_GNU_SOURCE $(UUID_CFLAGS) partclone_fstype_LDADD=-lvmfs -luuid endif if ENABLE_JFS sbin_PROGRAMS += partclone.jfs #partclone_jfs_SOURCES=main.c partclone.c progress.c jfs_devices.c jfs_devices.h jfsclone.c jfsclone.h partclone.h progress.h gettext.h partclone_jfs_SOURCES=main.c partclone.c progress.c jfsclone.c jfsclone.h partclone.h progress.h gettext.h partclone_jfs_CFLAGS=-DJFS partclone_jfs_LDADD=-luuid -ljfs endif if ENABLE_BTRFS sbin_PROGRAMS += partclone.btrfs partclone_btrfs_SOURCES=main.c partclone.c progress.c btrfsclone.c btrfsclone.h partclone.h progress.h gettext.h $(BTRFS_SOURCE) partclone_btrfs_CFLAGS=-DBTRFS -DBTRFS_FLAT_INCLUDES partclone_btrfs_LDADD=-luuid -lblkid endif if ENABLE_MINIX sbin_PROGRAMS += partclone.minix partclone_minix_SOURCES=main.c partclone.c progress.c minixclone.c minixclone.h partclone.h progress.h gettext.h partclone_minix_CFLAGS=-DMINIX endif # Extra install-exec-hook: if ENABLE_EXTFS $(LN_S) -f partclone.extfs $(DESTDIR)$(sbindir)/partclone.ext2 $(LN_S) -f partclone.extfs $(DESTDIR)$(sbindir)/partclone.ext3 $(LN_S) -f partclone.extfs $(DESTDIR)$(sbindir)/partclone.ext4 $(LN_S) -f partclone.extfs $(DESTDIR)$(sbindir)/partclone.ext4dev endif if ENABLE_HFSP $(LN_S) -f partclone.hfsp $(DESTDIR)$(sbindir)/partclone.hfs+ $(LN_S) -f partclone.hfsp $(DESTDIR)$(sbindir)/partclone.hfsplus endif if ENABLE_NTFS $(LN_S) -f partclone.ntfsfixboot $(DESTDIR)$(sbindir)/partclone.ntfsreloc endif if ENABLE_FAT $(LN_S) -f partclone.fat $(DESTDIR)$(sbindir)/partclone.fat12 $(LN_S) -f partclone.fat $(DESTDIR)$(sbindir)/partclone.fat16 $(LN_S) -f partclone.fat $(DESTDIR)$(sbindir)/partclone.fat32 $(LN_S) -f partclone.fat $(DESTDIR)$(sbindir)/partclone.vfat endif if ENABLE_VMFS $(LN_S) -f partclone.vmfs $(DESTDIR)$(sbindir)/partclone.VMFS_volume_member $(LN_S) -f partclone.vmfs $(DESTDIR)$(sbindir)/partclone.vmfs3 # $(LN_S) -f partclone.vmfs $(DESTDIR)$(sbindir)/partclone.vmfs5 endif uninstall-local: if ENABLE_EXTFS $(RM) -f $(sbindir)/partclone.ext4dev $(RM) -f $(sbindir)/partclone.ext4 $(RM) -f $(sbindir)/partclone.ext3 $(RM) -f $(sbindir)/partclone.ext2 endif if ENABLE_HFSP $(RM) -f $(sbindir)/partclone.hfs+ $(RM) -f $(sbindir)/partclone.hfsplus endif if ENABLE_FAT $(RM) -f $(sbindir)/partclone.fat12 $(RM) -f $(sbindir)/partclone.fat16 $(RM) -f $(sbindir)/partclone.fat32 $(RM) -f $(sbindir)/partclone.vfat endif if ENABLE_NTFS $(RM) -f $(sbindir)/partclone.ntfsreloc endif if ENABLE_VMFS $(RM) -f $(sbindir)/partclone.VMFS_volume_member endif FORCE: partclone-0.2.86/src/Makefile.in000066400000000000000000014220601262102574200164400ustar00rootroot00000000000000# Makefile.in generated by automake 1.15 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2014 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ sbin_PROGRAMS = partclone.info$(EXEEXT) partclone.dd$(EXEEXT) \ partclone.restore$(EXEEXT) partclone.chkimg$(EXEEXT) \ partclone.imager$(EXEEXT) $(am__EXEEXT_1) $(am__EXEEXT_2) \ $(am__EXEEXT_3) $(am__EXEEXT_4) $(am__EXEEXT_5) \ $(am__EXEEXT_6) $(am__EXEEXT_7) $(am__EXEEXT_8) \ $(am__EXEEXT_9) partclone.ntfsfixboot$(EXEEXT) \ $(am__EXEEXT_10) $(am__EXEEXT_11) $(am__EXEEXT_12) \ $(am__EXEEXT_13) $(am__EXEEXT_14) $(am__EXEEXT_15) @ENABLE_TINFO_TRUE@am__append_1 = -ltinfo @ENABLE_MEMTRACE_TRUE@am__append_2 = -DMEMTRACE -DMEMWATCH -DMW_STDIO @ENABLE_NCURSESW_TRUE@am__append_3 = -I/usr/include/ncursesw @ENABLE_EXTFS_TRUE@am__append_4 = partclone.extfs @ENABLE_REISERFS_TRUE@am__append_5 = partclone.reiserfs @ENABLE_REISER4_TRUE@am__append_6 = partclone.reiser4 @ENABLE_HFSP_TRUE@am__append_7 = partclone.hfsp @ENABLE_XFS_TRUE@am__append_8 = partclone.xfs @ENABLE_EXFAT_TRUE@am__append_9 = partclone.exfat @ENABLE_F2FS_TRUE@am__append_10 = partclone.f2fs @ENABLE_NILFS2_TRUE@am__append_11 = partclone.nilfs2 @ENABLE_FAT_TRUE@am__append_12 = partclone.fat @ENABLE_NTFS_TRUE@am__append_13 = partclone.ntfs @ENABLE_UFS_TRUE@am__append_14 = partclone.ufs @ENABLE_VMFS_TRUE@am__append_15 = partclone.vmfs partclone.vmfs5 \ @ENABLE_VMFS_TRUE@ partclone.fstype @ENABLE_JFS_TRUE@am__append_16 = partclone.jfs @ENABLE_BTRFS_TRUE@am__append_17 = partclone.btrfs @ENABLE_MINIX_TRUE@am__append_18 = partclone.minix subdir = src ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/gettext.m4 \ $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = @ENABLE_EXTFS_TRUE@am__EXEEXT_1 = partclone.extfs$(EXEEXT) @ENABLE_REISERFS_TRUE@am__EXEEXT_2 = partclone.reiserfs$(EXEEXT) @ENABLE_REISER4_TRUE@am__EXEEXT_3 = partclone.reiser4$(EXEEXT) @ENABLE_HFSP_TRUE@am__EXEEXT_4 = partclone.hfsp$(EXEEXT) @ENABLE_XFS_TRUE@am__EXEEXT_5 = partclone.xfs$(EXEEXT) @ENABLE_EXFAT_TRUE@am__EXEEXT_6 = partclone.exfat$(EXEEXT) @ENABLE_F2FS_TRUE@am__EXEEXT_7 = partclone.f2fs$(EXEEXT) @ENABLE_NILFS2_TRUE@am__EXEEXT_8 = partclone.nilfs2$(EXEEXT) @ENABLE_FAT_TRUE@am__EXEEXT_9 = partclone.fat$(EXEEXT) @ENABLE_NTFS_TRUE@am__EXEEXT_10 = partclone.ntfs$(EXEEXT) @ENABLE_UFS_TRUE@am__EXEEXT_11 = partclone.ufs$(EXEEXT) @ENABLE_VMFS_TRUE@am__EXEEXT_12 = partclone.vmfs$(EXEEXT) \ @ENABLE_VMFS_TRUE@ partclone.vmfs5$(EXEEXT) \ @ENABLE_VMFS_TRUE@ partclone.fstype$(EXEEXT) @ENABLE_JFS_TRUE@am__EXEEXT_13 = partclone.jfs$(EXEEXT) @ENABLE_BTRFS_TRUE@am__EXEEXT_14 = partclone.btrfs$(EXEEXT) @ENABLE_MINIX_TRUE@am__EXEEXT_15 = partclone.minix$(EXEEXT) am__installdirs = "$(DESTDIR)$(sbindir)" PROGRAMS = $(sbin_PROGRAMS) am__partclone_btrfs_SOURCES_DIST = main.c partclone.c progress.c \ btrfsclone.c btrfsclone.h partclone.h progress.h gettext.h \ btrfs/bitops.h btrfs/ctree.h btrfs/extent_io.c \ btrfs/inode-item.c btrfs/math.h btrfs/radix-tree.c \ btrfs/root-tree.c btrfs/ulist.c btrfs/volumes.c \ btrfs/btrfsck.h btrfs/dir-item.c btrfs/extent_io.h \ btrfs/inode-map.c btrfs/print-tree.c btrfs/radix-tree.h \ btrfs/send.h btrfs/ulist.h btrfs/volumes.h btrfs/btrfs-list.c \ btrfs/disk-io.c btrfs/extent-tree.c btrfs/ioctl.h \ btrfs/print-tree.h btrfs/raid6.c btrfs/send-stream.c \ btrfs/utils.c btrfs/btrfs-list.h btrfs/disk-io.h \ btrfs/file-item.c btrfs/kerncompat.h btrfs/qgroup.c \ btrfs/rbtree.c btrfs/send-stream.h btrfs/utils.h \ btrfs/crc32c.c btrfs/free-space-cache.c btrfs/list.h \ btrfs/qgroup.h btrfs/rbtree.h btrfs/send-utils.c \ btrfs/utils-lib.c btrfs/rbtree-utils.c btrfs/crc32c.h \ btrfs/extent-cache.c btrfs/free-space-cache.h \ btrfs/list_sort.c btrfs/qgroup-verify.c btrfs/repair.c \ btrfs/send-utils.h btrfs/uuid-tree.c btrfs/ctree.c \ btrfs/extent-cache.h btrfs/hash.h btrfs/list_sort.h \ btrfs/qgroup-verify.h btrfs/repair.h btrfs/transaction.h \ btrfs/version.h btrfs/rbtree-utils.h btrfs/rbtree_augmented.h am__dirstamp = $(am__leading_dot)dirstamp am__objects_1 = btrfs/partclone_btrfs-extent_io.$(OBJEXT) \ btrfs/partclone_btrfs-inode-item.$(OBJEXT) \ btrfs/partclone_btrfs-radix-tree.$(OBJEXT) \ btrfs/partclone_btrfs-root-tree.$(OBJEXT) \ btrfs/partclone_btrfs-ulist.$(OBJEXT) \ btrfs/partclone_btrfs-volumes.$(OBJEXT) \ btrfs/partclone_btrfs-dir-item.$(OBJEXT) \ btrfs/partclone_btrfs-inode-map.$(OBJEXT) \ btrfs/partclone_btrfs-print-tree.$(OBJEXT) \ btrfs/partclone_btrfs-btrfs-list.$(OBJEXT) \ btrfs/partclone_btrfs-disk-io.$(OBJEXT) \ btrfs/partclone_btrfs-extent-tree.$(OBJEXT) \ btrfs/partclone_btrfs-raid6.$(OBJEXT) \ btrfs/partclone_btrfs-send-stream.$(OBJEXT) \ btrfs/partclone_btrfs-utils.$(OBJEXT) \ btrfs/partclone_btrfs-file-item.$(OBJEXT) \ btrfs/partclone_btrfs-qgroup.$(OBJEXT) \ btrfs/partclone_btrfs-rbtree.$(OBJEXT) \ btrfs/partclone_btrfs-crc32c.$(OBJEXT) \ btrfs/partclone_btrfs-free-space-cache.$(OBJEXT) \ btrfs/partclone_btrfs-send-utils.$(OBJEXT) \ btrfs/partclone_btrfs-utils-lib.$(OBJEXT) \ btrfs/partclone_btrfs-rbtree-utils.$(OBJEXT) \ btrfs/partclone_btrfs-extent-cache.$(OBJEXT) \ btrfs/partclone_btrfs-list_sort.$(OBJEXT) \ btrfs/partclone_btrfs-qgroup-verify.$(OBJEXT) \ btrfs/partclone_btrfs-repair.$(OBJEXT) \ btrfs/partclone_btrfs-uuid-tree.$(OBJEXT) \ btrfs/partclone_btrfs-ctree.$(OBJEXT) @ENABLE_BTRFS_TRUE@am_partclone_btrfs_OBJECTS = \ @ENABLE_BTRFS_TRUE@ partclone_btrfs-main.$(OBJEXT) \ @ENABLE_BTRFS_TRUE@ partclone_btrfs-partclone.$(OBJEXT) \ @ENABLE_BTRFS_TRUE@ partclone_btrfs-progress.$(OBJEXT) \ @ENABLE_BTRFS_TRUE@ partclone_btrfs-btrfsclone.$(OBJEXT) \ @ENABLE_BTRFS_TRUE@ $(am__objects_1) partclone_btrfs_OBJECTS = $(am_partclone_btrfs_OBJECTS) partclone_btrfs_DEPENDENCIES = partclone_btrfs_LINK = $(CCLD) $(partclone_btrfs_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ am_partclone_chkimg_OBJECTS = partclone_chkimg-main.$(OBJEXT) \ partclone_chkimg-partclone.$(OBJEXT) \ partclone_chkimg-progress.$(OBJEXT) \ partclone_chkimg-ddclone.$(OBJEXT) partclone_chkimg_OBJECTS = $(am_partclone_chkimg_OBJECTS) partclone_chkimg_LDADD = $(LDADD) am__DEPENDENCIES_1 = partclone_chkimg_DEPENDENCIES = $(am__DEPENDENCIES_1) partclone_chkimg_LINK = $(CCLD) $(partclone_chkimg_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ am_partclone_dd_OBJECTS = partclone_dd-main.$(OBJEXT) \ partclone_dd-partclone.$(OBJEXT) \ partclone_dd-progress.$(OBJEXT) partclone_dd-ddclone.$(OBJEXT) partclone_dd_OBJECTS = $(am_partclone_dd_OBJECTS) partclone_dd_LDADD = $(LDADD) partclone_dd_DEPENDENCIES = $(am__DEPENDENCIES_1) partclone_dd_LINK = $(CCLD) $(partclone_dd_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ am__partclone_exfat_SOURCES_DIST = main.c partclone.c progress.c \ exfatclone.c exfatclone.h partclone.h progress.h gettext.h \ exfat/cluster.c exfat/utf.c exfat/utils.c exfat/lookup.c \ exfat/io.c exfat/log.c exfat/node.c exfat/mount.c exfat/time.c am__objects_2 = exfat/partclone_exfat-cluster.$(OBJEXT) \ exfat/partclone_exfat-utf.$(OBJEXT) \ exfat/partclone_exfat-utils.$(OBJEXT) \ exfat/partclone_exfat-lookup.$(OBJEXT) \ exfat/partclone_exfat-io.$(OBJEXT) \ exfat/partclone_exfat-log.$(OBJEXT) \ exfat/partclone_exfat-node.$(OBJEXT) \ exfat/partclone_exfat-mount.$(OBJEXT) \ exfat/partclone_exfat-time.$(OBJEXT) @ENABLE_EXFAT_TRUE@am_partclone_exfat_OBJECTS = \ @ENABLE_EXFAT_TRUE@ partclone_exfat-main.$(OBJEXT) \ @ENABLE_EXFAT_TRUE@ partclone_exfat-partclone.$(OBJEXT) \ @ENABLE_EXFAT_TRUE@ partclone_exfat-progress.$(OBJEXT) \ @ENABLE_EXFAT_TRUE@ partclone_exfat-exfatclone.$(OBJEXT) \ @ENABLE_EXFAT_TRUE@ $(am__objects_2) partclone_exfat_OBJECTS = $(am_partclone_exfat_OBJECTS) partclone_exfat_LDADD = $(LDADD) partclone_exfat_DEPENDENCIES = $(am__DEPENDENCIES_1) partclone_exfat_LINK = $(CCLD) $(partclone_exfat_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ am__partclone_extfs_SOURCES_DIST = main.c partclone.c progress.c \ extfsclone.c extfsclone.h partclone.h progress.h gettext.h @ENABLE_EXTFS_TRUE@am_partclone_extfs_OBJECTS = \ @ENABLE_EXTFS_TRUE@ partclone_extfs-main.$(OBJEXT) \ @ENABLE_EXTFS_TRUE@ partclone_extfs-partclone.$(OBJEXT) \ @ENABLE_EXTFS_TRUE@ partclone_extfs-progress.$(OBJEXT) \ @ENABLE_EXTFS_TRUE@ partclone_extfs-extfsclone.$(OBJEXT) partclone_extfs_OBJECTS = $(am_partclone_extfs_OBJECTS) partclone_extfs_DEPENDENCIES = partclone_extfs_LINK = $(CCLD) $(partclone_extfs_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ am__partclone_f2fs_SOURCES_DIST = main.c partclone.c progress.c \ f2fsclone.c f2fsclone.h partclone.h progress.h gettext.h \ f2fs/fsck.c f2fs/libf2fs.c f2fs/fsck.h f2fs/mount.c \ f2fs/f2fs_fs.h f2fs/list.h f2fs/f2fs.h am__objects_3 = f2fs/partclone_f2fs-fsck.$(OBJEXT) \ f2fs/partclone_f2fs-libf2fs.$(OBJEXT) \ f2fs/partclone_f2fs-mount.$(OBJEXT) @ENABLE_F2FS_TRUE@am_partclone_f2fs_OBJECTS = \ @ENABLE_F2FS_TRUE@ partclone_f2fs-main.$(OBJEXT) \ @ENABLE_F2FS_TRUE@ partclone_f2fs-partclone.$(OBJEXT) \ @ENABLE_F2FS_TRUE@ partclone_f2fs-progress.$(OBJEXT) \ @ENABLE_F2FS_TRUE@ partclone_f2fs-f2fsclone.$(OBJEXT) \ @ENABLE_F2FS_TRUE@ $(am__objects_3) partclone_f2fs_OBJECTS = $(am_partclone_f2fs_OBJECTS) partclone_f2fs_DEPENDENCIES = partclone_f2fs_LINK = $(CCLD) $(partclone_f2fs_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ am__partclone_fat_SOURCES_DIST = main.c partclone.c progress.c \ fatclone.c fatclone.h partclone.h progress.h gettext.h @ENABLE_FAT_TRUE@am_partclone_fat_OBJECTS = \ @ENABLE_FAT_TRUE@ partclone_fat-main.$(OBJEXT) \ @ENABLE_FAT_TRUE@ partclone_fat-partclone.$(OBJEXT) \ @ENABLE_FAT_TRUE@ partclone_fat-progress.$(OBJEXT) \ @ENABLE_FAT_TRUE@ partclone_fat-fatclone.$(OBJEXT) partclone_fat_OBJECTS = $(am_partclone_fat_OBJECTS) partclone_fat_LDADD = $(LDADD) partclone_fat_DEPENDENCIES = $(am__DEPENDENCIES_1) partclone_fat_LINK = $(CCLD) $(partclone_fat_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ am__partclone_fstype_SOURCES_DIST = fstype.c @ENABLE_VMFS_TRUE@am_partclone_fstype_OBJECTS = \ @ENABLE_VMFS_TRUE@ partclone_fstype-fstype.$(OBJEXT) partclone_fstype_OBJECTS = $(am_partclone_fstype_OBJECTS) partclone_fstype_DEPENDENCIES = partclone_fstype_LINK = $(CCLD) $(partclone_fstype_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ am__partclone_hfsp_SOURCES_DIST = main.c partclone.c progress.c \ hfsplusclone.c hfsplusclone.h partclone.h progress.h gettext.h @ENABLE_HFSP_TRUE@am_partclone_hfsp_OBJECTS = \ @ENABLE_HFSP_TRUE@ partclone_hfsp-main.$(OBJEXT) \ @ENABLE_HFSP_TRUE@ partclone_hfsp-partclone.$(OBJEXT) \ @ENABLE_HFSP_TRUE@ partclone_hfsp-progress.$(OBJEXT) \ @ENABLE_HFSP_TRUE@ partclone_hfsp-hfsplusclone.$(OBJEXT) partclone_hfsp_OBJECTS = $(am_partclone_hfsp_OBJECTS) partclone_hfsp_LDADD = $(LDADD) partclone_hfsp_DEPENDENCIES = $(am__DEPENDENCIES_1) partclone_hfsp_LINK = $(CCLD) $(partclone_hfsp_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ am_partclone_imager_OBJECTS = partclone_imager-main.$(OBJEXT) \ partclone_imager-partclone.$(OBJEXT) \ partclone_imager-progress.$(OBJEXT) \ partclone_imager-ddclone.$(OBJEXT) partclone_imager_OBJECTS = $(am_partclone_imager_OBJECTS) partclone_imager_LDADD = $(LDADD) partclone_imager_DEPENDENCIES = $(am__DEPENDENCIES_1) partclone_imager_LINK = $(CCLD) $(partclone_imager_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ am_partclone_info_OBJECTS = info.$(OBJEXT) partclone.$(OBJEXT) partclone_info_OBJECTS = $(am_partclone_info_OBJECTS) partclone_info_LDADD = $(LDADD) partclone_info_DEPENDENCIES = $(am__DEPENDENCIES_1) am__partclone_jfs_SOURCES_DIST = main.c partclone.c progress.c \ jfsclone.c jfsclone.h partclone.h progress.h gettext.h @ENABLE_JFS_TRUE@am_partclone_jfs_OBJECTS = \ @ENABLE_JFS_TRUE@ partclone_jfs-main.$(OBJEXT) \ @ENABLE_JFS_TRUE@ partclone_jfs-partclone.$(OBJEXT) \ @ENABLE_JFS_TRUE@ partclone_jfs-progress.$(OBJEXT) \ @ENABLE_JFS_TRUE@ partclone_jfs-jfsclone.$(OBJEXT) partclone_jfs_OBJECTS = $(am_partclone_jfs_OBJECTS) partclone_jfs_DEPENDENCIES = partclone_jfs_LINK = $(CCLD) $(partclone_jfs_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ am__partclone_minix_SOURCES_DIST = main.c partclone.c progress.c \ minixclone.c minixclone.h partclone.h progress.h gettext.h @ENABLE_MINIX_TRUE@am_partclone_minix_OBJECTS = \ @ENABLE_MINIX_TRUE@ partclone_minix-main.$(OBJEXT) \ @ENABLE_MINIX_TRUE@ partclone_minix-partclone.$(OBJEXT) \ @ENABLE_MINIX_TRUE@ partclone_minix-progress.$(OBJEXT) \ @ENABLE_MINIX_TRUE@ partclone_minix-minixclone.$(OBJEXT) partclone_minix_OBJECTS = $(am_partclone_minix_OBJECTS) partclone_minix_LDADD = $(LDADD) partclone_minix_DEPENDENCIES = $(am__DEPENDENCIES_1) partclone_minix_LINK = $(CCLD) $(partclone_minix_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ am__partclone_nilfs2_SOURCES_DIST = main.c partclone.c progress.c \ nilfsclone.c nilfsclone.h partclone.h progress.h gettext.h @ENABLE_NILFS2_TRUE@am_partclone_nilfs2_OBJECTS = \ @ENABLE_NILFS2_TRUE@ partclone_nilfs2-main.$(OBJEXT) \ @ENABLE_NILFS2_TRUE@ partclone_nilfs2-partclone.$(OBJEXT) \ @ENABLE_NILFS2_TRUE@ partclone_nilfs2-progress.$(OBJEXT) \ @ENABLE_NILFS2_TRUE@ partclone_nilfs2-nilfsclone.$(OBJEXT) partclone_nilfs2_OBJECTS = $(am_partclone_nilfs2_OBJECTS) partclone_nilfs2_DEPENDENCIES = partclone_nilfs2_LINK = $(CCLD) $(partclone_nilfs2_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ am__partclone_ntfs_SOURCES_DIST = main.c partclone.c progress.c \ ntfsclone-ng.c ntfsclone-ng.h partclone.h progress.h gettext.h @ENABLE_NTFS_TRUE@am_partclone_ntfs_OBJECTS = \ @ENABLE_NTFS_TRUE@ partclone_ntfs-main.$(OBJEXT) \ @ENABLE_NTFS_TRUE@ partclone_ntfs-partclone.$(OBJEXT) \ @ENABLE_NTFS_TRUE@ partclone_ntfs-progress.$(OBJEXT) \ @ENABLE_NTFS_TRUE@ partclone_ntfs-ntfsclone-ng.$(OBJEXT) partclone_ntfs_OBJECTS = $(am_partclone_ntfs_OBJECTS) partclone_ntfs_DEPENDENCIES = partclone_ntfs_LINK = $(CCLD) $(partclone_ntfs_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ am_partclone_ntfsfixboot_OBJECTS = ntfsfixboot.$(OBJEXT) partclone_ntfsfixboot_OBJECTS = $(am_partclone_ntfsfixboot_OBJECTS) partclone_ntfsfixboot_LDADD = $(LDADD) partclone_ntfsfixboot_DEPENDENCIES = $(am__DEPENDENCIES_1) am__partclone_reiser4_SOURCES_DIST = main.c partclone.c progress.c \ reiser4clone.c reiser4clone.h partclone.h progress.h gettext.h @ENABLE_REISER4_TRUE@am_partclone_reiser4_OBJECTS = \ @ENABLE_REISER4_TRUE@ partclone_reiser4-main.$(OBJEXT) \ @ENABLE_REISER4_TRUE@ partclone_reiser4-partclone.$(OBJEXT) \ @ENABLE_REISER4_TRUE@ partclone_reiser4-progress.$(OBJEXT) \ @ENABLE_REISER4_TRUE@ partclone_reiser4-reiser4clone.$(OBJEXT) partclone_reiser4_OBJECTS = $(am_partclone_reiser4_OBJECTS) partclone_reiser4_DEPENDENCIES = partclone_reiser4_LINK = $(CCLD) $(partclone_reiser4_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ am__partclone_reiserfs_SOURCES_DIST = main.c partclone.c progress.c \ reiserfsclone.c reiserfsclone.h partclone.h progress.h \ gettext.h @ENABLE_REISERFS_TRUE@am_partclone_reiserfs_OBJECTS = \ @ENABLE_REISERFS_TRUE@ partclone_reiserfs-main.$(OBJEXT) \ @ENABLE_REISERFS_TRUE@ partclone_reiserfs-partclone.$(OBJEXT) \ @ENABLE_REISERFS_TRUE@ partclone_reiserfs-progress.$(OBJEXT) \ @ENABLE_REISERFS_TRUE@ partclone_reiserfs-reiserfsclone.$(OBJEXT) partclone_reiserfs_OBJECTS = $(am_partclone_reiserfs_OBJECTS) partclone_reiserfs_DEPENDENCIES = partclone_reiserfs_LINK = $(CCLD) $(partclone_reiserfs_CFLAGS) \ $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ am_partclone_restore_OBJECTS = partclone_restore-main.$(OBJEXT) \ partclone_restore-partclone.$(OBJEXT) \ partclone_restore-progress.$(OBJEXT) \ partclone_restore-ddclone.$(OBJEXT) partclone_restore_OBJECTS = $(am_partclone_restore_OBJECTS) partclone_restore_LDADD = $(LDADD) partclone_restore_DEPENDENCIES = $(am__DEPENDENCIES_1) partclone_restore_LINK = $(CCLD) $(partclone_restore_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ am__partclone_ufs_SOURCES_DIST = main.c partclone.c progress.c \ ufsclone.c ufsclone.h partclone.h progress.h gettext.h @ENABLE_UFS_TRUE@am_partclone_ufs_OBJECTS = \ @ENABLE_UFS_TRUE@ partclone_ufs-main.$(OBJEXT) \ @ENABLE_UFS_TRUE@ partclone_ufs-partclone.$(OBJEXT) \ @ENABLE_UFS_TRUE@ partclone_ufs-progress.$(OBJEXT) \ @ENABLE_UFS_TRUE@ partclone_ufs-ufsclone.$(OBJEXT) partclone_ufs_OBJECTS = $(am_partclone_ufs_OBJECTS) partclone_ufs_DEPENDENCIES = partclone_ufs_LINK = $(CCLD) $(partclone_ufs_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ am__partclone_vmfs_SOURCES_DIST = main.c partclone.c progress.c \ vmfsclone.c vmfsclone.h partclone.h progress.h gettext.h @ENABLE_VMFS_TRUE@am_partclone_vmfs_OBJECTS = \ @ENABLE_VMFS_TRUE@ partclone_vmfs-main.$(OBJEXT) \ @ENABLE_VMFS_TRUE@ partclone_vmfs-partclone.$(OBJEXT) \ @ENABLE_VMFS_TRUE@ partclone_vmfs-progress.$(OBJEXT) \ @ENABLE_VMFS_TRUE@ partclone_vmfs-vmfsclone.$(OBJEXT) partclone_vmfs_OBJECTS = $(am_partclone_vmfs_OBJECTS) partclone_vmfs_DEPENDENCIES = partclone_vmfs_LINK = $(CCLD) $(partclone_vmfs_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ am__partclone_vmfs5_SOURCES_DIST = main.c partclone.c progress.c \ vmfs5clone.c vmfsclone.h partclone.h progress.h gettext.h @ENABLE_VMFS_TRUE@am_partclone_vmfs5_OBJECTS = \ @ENABLE_VMFS_TRUE@ partclone_vmfs5-main.$(OBJEXT) \ @ENABLE_VMFS_TRUE@ partclone_vmfs5-partclone.$(OBJEXT) \ @ENABLE_VMFS_TRUE@ partclone_vmfs5-progress.$(OBJEXT) \ @ENABLE_VMFS_TRUE@ partclone_vmfs5-vmfs5clone.$(OBJEXT) partclone_vmfs5_OBJECTS = $(am_partclone_vmfs5_OBJECTS) partclone_vmfs5_DEPENDENCIES = partclone_vmfs5_LINK = $(CCLD) $(partclone_vmfs5_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ am__partclone_xfs_SOURCES_DIST = main.c partclone.c progress.c \ xfsclone.c xfsclone.h partclone.h progress.h gettext.h \ xfs/atomic.h xfs/libxfs_priv.h xfs/xfs_arch.h \ xfs/xfs_da_format.h xfs/xfs_inode_fork.h xfs/bitops.h \ xfs/libxlog.h xfs/xfs_attr.c xfs/xfs_dir2_block.c \ xfs/xfs_inode.h xfs/cache.c xfs/linux.c xfs/xfs_attr_leaf.c \ xfs/xfs_dir2.c xfs/xfs_log_format.h xfs/cache.h xfs/linux.h \ xfs/xfs_attr_leaf.h xfs/xfs_dir2_data.c xfs/xfs_log_recover.h \ xfs/command.h xfs/list.h xfs/xfs_attr_remote.c xfs/xfs_dir2.h \ xfs/xfs_log_rlimit.c xfs/crc32.c xfs/logitem.c \ xfs/xfs_attr_remote.h xfs/xfs_dir2_leaf.c xfs/xfs_metadump.h \ xfs/crc32defs.h xfs/parent.h xfs/xfs_attr_sf.h \ xfs/xfs_dir2_node.c xfs/xfs_mount.h xfs/path.h xfs/xfs_bit.c \ xfs/xfs_dir2_priv.h xfs/xfs_quota_defs.h xfs/platform_defs.h \ xfs/xfs_bit.h xfs/xfs_dir2_sf.c xfs/xfs_rtbitmap.c \ xfs/handle.h xfs/platform_defs.h.in xfs/xfs_bmap_btree.c \ xfs/xfs_dquot_buf.c xfs/xfs_sb.c xfs/hlist.h xfs/project.h \ xfs/xfs_bmap_btree.h xfs/xfs_format.h xfs/xfs_sb.h xfs/init.c \ xfs/radix-tree.c xfs/xfs_bmap.c xfs/xfs_fs.h xfs/xfs_shared.h \ xfs/init.h xfs/radix-tree.h xfs/xfs_bmap.h xfs/xfs.h \ xfs/xfs_symlink_remote.c xfs/input.h xfs/rdwr.c \ xfs/xfs_btree.c xfs/xfs_ialloc_btree.c xfs/xfs_trace.h \ xfs/jdm.h xfs/trans.c xfs/xfs_btree.h xfs/xfs_ialloc_btree.h \ xfs/xfs_trans.h xfs/kmem.c xfs/util.c xfs/xfs_btree_trace.h \ xfs/xfs_ialloc.c xfs/xfs_trans_resv.c xfs/kmem.h \ xfs/xfs_alloc_btree.c xfs/xfs_cksum.h xfs/xfs_ialloc.h \ xfs/xfs_trans_resv.h xfs/libxfs_api_defs.h \ xfs/xfs_alloc_btree.h xfs/xfs_da_btree.c xfs/xfs_inode_buf.c \ xfs/xfs_trans_space.h xfs/libxfs.h xfs/xfs_alloc.c \ xfs/xfs_da_btree.h xfs/xfs_inode_buf.h xfs/xfs_types.h \ xfs/libxfs_io.h xfs/xfs_alloc.h xfs/xfs_da_format.c \ xfs/xfs_inode_fork.c xfs/xqm.h xfs/crc32table.h am__objects_4 = xfs/partclone_xfs-xfs_attr.$(OBJEXT) \ xfs/partclone_xfs-xfs_dir2_block.$(OBJEXT) \ xfs/partclone_xfs-cache.$(OBJEXT) \ xfs/partclone_xfs-linux.$(OBJEXT) \ xfs/partclone_xfs-xfs_attr_leaf.$(OBJEXT) \ xfs/partclone_xfs-xfs_dir2.$(OBJEXT) \ xfs/partclone_xfs-xfs_dir2_data.$(OBJEXT) \ xfs/partclone_xfs-xfs_attr_remote.$(OBJEXT) \ xfs/partclone_xfs-xfs_log_rlimit.$(OBJEXT) \ xfs/partclone_xfs-crc32.$(OBJEXT) \ xfs/partclone_xfs-logitem.$(OBJEXT) \ xfs/partclone_xfs-xfs_dir2_leaf.$(OBJEXT) \ xfs/partclone_xfs-xfs_dir2_node.$(OBJEXT) \ xfs/partclone_xfs-xfs_bit.$(OBJEXT) \ xfs/partclone_xfs-xfs_dir2_sf.$(OBJEXT) \ xfs/partclone_xfs-xfs_rtbitmap.$(OBJEXT) \ xfs/partclone_xfs-xfs_bmap_btree.$(OBJEXT) \ xfs/partclone_xfs-xfs_dquot_buf.$(OBJEXT) \ xfs/partclone_xfs-xfs_sb.$(OBJEXT) \ xfs/partclone_xfs-init.$(OBJEXT) \ xfs/partclone_xfs-radix-tree.$(OBJEXT) \ xfs/partclone_xfs-xfs_bmap.$(OBJEXT) \ xfs/partclone_xfs-xfs_symlink_remote.$(OBJEXT) \ xfs/partclone_xfs-rdwr.$(OBJEXT) \ xfs/partclone_xfs-xfs_btree.$(OBJEXT) \ xfs/partclone_xfs-xfs_ialloc_btree.$(OBJEXT) \ xfs/partclone_xfs-trans.$(OBJEXT) \ xfs/partclone_xfs-kmem.$(OBJEXT) \ xfs/partclone_xfs-util.$(OBJEXT) \ xfs/partclone_xfs-xfs_ialloc.$(OBJEXT) \ xfs/partclone_xfs-xfs_trans_resv.$(OBJEXT) \ xfs/partclone_xfs-xfs_alloc_btree.$(OBJEXT) \ xfs/partclone_xfs-xfs_da_btree.$(OBJEXT) \ xfs/partclone_xfs-xfs_inode_buf.$(OBJEXT) \ xfs/partclone_xfs-xfs_alloc.$(OBJEXT) \ xfs/partclone_xfs-xfs_da_format.$(OBJEXT) \ xfs/partclone_xfs-xfs_inode_fork.$(OBJEXT) @ENABLE_XFS_TRUE@am_partclone_xfs_OBJECTS = \ @ENABLE_XFS_TRUE@ partclone_xfs-main.$(OBJEXT) \ @ENABLE_XFS_TRUE@ partclone_xfs-partclone.$(OBJEXT) \ @ENABLE_XFS_TRUE@ partclone_xfs-progress.$(OBJEXT) \ @ENABLE_XFS_TRUE@ partclone_xfs-xfsclone.$(OBJEXT) \ @ENABLE_XFS_TRUE@ $(am__objects_4) partclone_xfs_OBJECTS = $(am_partclone_xfs_OBJECTS) partclone_xfs_DEPENDENCIES = partclone_xfs_LINK = $(CCLD) $(partclone_xfs_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(partclone_btrfs_SOURCES) $(partclone_chkimg_SOURCES) \ $(partclone_dd_SOURCES) $(partclone_exfat_SOURCES) \ $(partclone_extfs_SOURCES) $(partclone_f2fs_SOURCES) \ $(partclone_fat_SOURCES) $(partclone_fstype_SOURCES) \ $(partclone_hfsp_SOURCES) $(partclone_imager_SOURCES) \ $(partclone_info_SOURCES) $(partclone_jfs_SOURCES) \ $(partclone_minix_SOURCES) $(partclone_nilfs2_SOURCES) \ $(partclone_ntfs_SOURCES) $(partclone_ntfsfixboot_SOURCES) \ $(partclone_reiser4_SOURCES) $(partclone_reiserfs_SOURCES) \ $(partclone_restore_SOURCES) $(partclone_ufs_SOURCES) \ $(partclone_vmfs_SOURCES) $(partclone_vmfs5_SOURCES) \ $(partclone_xfs_SOURCES) DIST_SOURCES = $(am__partclone_btrfs_SOURCES_DIST) \ $(partclone_chkimg_SOURCES) $(partclone_dd_SOURCES) \ $(am__partclone_exfat_SOURCES_DIST) \ $(am__partclone_extfs_SOURCES_DIST) \ $(am__partclone_f2fs_SOURCES_DIST) \ $(am__partclone_fat_SOURCES_DIST) \ $(am__partclone_fstype_SOURCES_DIST) \ $(am__partclone_hfsp_SOURCES_DIST) $(partclone_imager_SOURCES) \ $(partclone_info_SOURCES) $(am__partclone_jfs_SOURCES_DIST) \ $(am__partclone_minix_SOURCES_DIST) \ $(am__partclone_nilfs2_SOURCES_DIST) \ $(am__partclone_ntfs_SOURCES_DIST) \ $(partclone_ntfsfixboot_SOURCES) \ $(am__partclone_reiser4_SOURCES_DIST) \ $(am__partclone_reiserfs_SOURCES_DIST) \ $(partclone_restore_SOURCES) $(am__partclone_ufs_SOURCES_DIST) \ $(am__partclone_vmfs_SOURCES_DIST) \ $(am__partclone_vmfs5_SOURCES_DIST) \ $(am__partclone_xfs_SOURCES_DIST) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXT2FS_CFLAGS = @EXT2FS_CFLAGS@ EXT2FS_LIBS = @EXT2FS_LIBS@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ LDFLAGS = @LDFLAGS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ $(am__append_1) LN_S = @LN_S@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ NTFS_CFLAGS = @NTFS_CFLAGS@ NTFS_LIBS = @NTFS_LIBS@ OBJEXT = @OBJEXT@ ORIGINAL_CFLAGS = @ORIGINAL_CFLAGS@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ POSUB = @POSUB@ RM = @RM@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ USE_NLS = @USE_NLS@ UUID_CFLAGS = @UUID_CFLAGS@ UUID_LIBS = @UUID_LIBS@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = subdir-objects AM_CPPFLAGS = -DLOCALEDIR=\"$(localedir)\" -D_FILE_OFFSET_BITS=64 LDADD = $(LIBINTL) TOOLBOX = srcdir=$(top_srcdir) builddir=$(top_builddir) $(top_srcdir)/toolbox BTRFS_SOURCE = \ btrfs/bitops.h btrfs/ctree.h btrfs/extent_io.c btrfs/inode-item.c btrfs/math.h btrfs/radix-tree.c btrfs/root-tree.c btrfs/ulist.c btrfs/volumes.c\ btrfs/btrfsck.h btrfs/dir-item.c btrfs/extent_io.h btrfs/inode-map.c btrfs/print-tree.c btrfs/radix-tree.h btrfs/send.h btrfs/ulist.h btrfs/volumes.h\ btrfs/btrfs-list.c btrfs/disk-io.c btrfs/extent-tree.c btrfs/ioctl.h btrfs/print-tree.h btrfs/raid6.c btrfs/send-stream.c btrfs/utils.c\ btrfs/btrfs-list.h btrfs/disk-io.h btrfs/file-item.c btrfs/kerncompat.h btrfs/qgroup.c btrfs/rbtree.c btrfs/send-stream.h btrfs/utils.h\ btrfs/crc32c.c btrfs/free-space-cache.c btrfs/list.h btrfs/qgroup.h btrfs/rbtree.h btrfs/send-utils.c btrfs/utils-lib.c btrfs/rbtree-utils.c\ btrfs/crc32c.h btrfs/extent-cache.c btrfs/free-space-cache.h btrfs/list_sort.c btrfs/qgroup-verify.c btrfs/repair.c btrfs/send-utils.h\ btrfs/uuid-tree.c btrfs/ctree.c btrfs/extent-cache.h btrfs/hash.h btrfs/list_sort.h btrfs/qgroup-verify.h btrfs/repair.h btrfs/transaction.h\ btrfs/version.h btrfs/rbtree-utils.h btrfs/rbtree_augmented.h XFS_SOURCE = \ xfs/atomic.h xfs/libxfs_priv.h xfs/xfs_arch.h xfs/xfs_da_format.h xfs/xfs_inode_fork.h xfs/bitops.h xfs/libxlog.h xfs/xfs_attr.c xfs/xfs_dir2_block.c xfs/xfs_inode.h xfs/cache.c xfs/linux.c xfs/xfs_attr_leaf.c xfs/xfs_dir2.c xfs/xfs_log_format.h xfs/cache.h xfs/linux.h xfs/xfs_attr_leaf.h xfs/xfs_dir2_data.c xfs/xfs_log_recover.h xfs/command.h xfs/list.h xfs/xfs_attr_remote.c xfs/xfs_dir2.h xfs/xfs_log_rlimit.c xfs/crc32.c xfs/logitem.c xfs/xfs_attr_remote.h xfs/xfs_dir2_leaf.c xfs/xfs_metadump.h xfs/crc32defs.h xfs/parent.h xfs/xfs_attr_sf.h xfs/xfs_dir2_node.c xfs/xfs_mount.h xfs/path.h xfs/xfs_bit.c xfs/xfs_dir2_priv.h xfs/xfs_quota_defs.h xfs/platform_defs.h xfs/xfs_bit.h xfs/xfs_dir2_sf.c xfs/xfs_rtbitmap.c xfs/handle.h xfs/platform_defs.h.in xfs/xfs_bmap_btree.c xfs/xfs_dquot_buf.c xfs/xfs_sb.c xfs/hlist.h xfs/project.h xfs/xfs_bmap_btree.h xfs/xfs_format.h xfs/xfs_sb.h xfs/init.c xfs/radix-tree.c xfs/xfs_bmap.c xfs/xfs_fs.h xfs/xfs_shared.h xfs/init.h xfs/radix-tree.h xfs/xfs_bmap.h xfs/xfs.h xfs/xfs_symlink_remote.c xfs/input.h xfs/rdwr.c xfs/xfs_btree.c xfs/xfs_ialloc_btree.c xfs/xfs_trace.h xfs/jdm.h xfs/trans.c xfs/xfs_btree.h xfs/xfs_ialloc_btree.h xfs/xfs_trans.h xfs/kmem.c xfs/util.c xfs/xfs_btree_trace.h xfs/xfs_ialloc.c xfs/xfs_trans_resv.c xfs/kmem.h xfs/xfs_alloc_btree.c xfs/xfs_cksum.h xfs/xfs_ialloc.h xfs/xfs_trans_resv.h xfs/libxfs_api_defs.h xfs/xfs_alloc_btree.h xfs/xfs_da_btree.c xfs/xfs_inode_buf.c xfs/xfs_trans_space.h xfs/libxfs.h xfs/xfs_alloc.c xfs/xfs_da_btree.h xfs/xfs_inode_buf.h xfs/xfs_types.h xfs/libxfs_io.h xfs/xfs_alloc.h xfs/xfs_da_format.c xfs/xfs_inode_fork.c xfs/xqm.h xfs/crc32table.h EXFATFS_SOURCE = exfat/cluster.c exfat/utf.c exfat/utils.c exfat/lookup.c exfat/io.c exfat/log.c exfat/node.c exfat/mount.c exfat/time.c F2FS_SOURCE = f2fs/fsck.c f2fs/libf2fs.c f2fs/fsck.h f2fs/mount.c f2fs/f2fs_fs.h f2fs/list.h f2fs/f2fs.h @ENABLE_STATIC_TRUE@AM_LDFLAGS = -static AM_CFLAGS = -D_FILE_OFFSET_BITS=64 $(am__append_2) $(am__append_3) partclone_info_SOURCES = info.c partclone.c partclone.h fs_common.h partclone_restore_SOURCES = main.c partclone.c progress.c ddclone.c ddclone.h partclone.h progress.h gettext.h partclone_restore_CFLAGS = -DRESTORE -DDD partclone_chkimg_SOURCES = main.c partclone.c progress.c ddclone.c ddclone.h partclone.h progress.h gettext.h partclone_chkimg_CFLAGS = -DCHKIMG -DDD partclone_dd_SOURCES = main.c partclone.c progress.c ddclone.c ddclone.h partclone.h progress.h gettext.h partclone_dd_CFLAGS = -DDD partclone_imager_SOURCES = main.c partclone.c progress.c ddclone.c ddclone.h partclone.h progress.h gettext.h partclone_imager_CFLAGS = -DIMG @ENABLE_EXTFS_TRUE@partclone_extfs_SOURCES = main.c partclone.c progress.c extfsclone.c extfsclone.h partclone.h progress.h gettext.h @ENABLE_EXTFS_TRUE@partclone_extfs_CFLAGS = -DEXTFS @ENABLE_EXTFS_TRUE@partclone_extfs_LDADD = -lext2fs -lcom_err -lpthread @ENABLE_REISERFS_TRUE@partclone_reiserfs_SOURCES = main.c partclone.c progress.c reiserfsclone.c reiserfsclone.h partclone.h progress.h gettext.h @ENABLE_REISERFS_TRUE@partclone_reiserfs_CFLAGS = -DREISERFS @ENABLE_REISERFS_TRUE@partclone_reiserfs_LDADD = -lreiserfs -ldal @ENABLE_REISER4_TRUE@partclone_reiser4_SOURCES = main.c partclone.c progress.c reiser4clone.c reiser4clone.h partclone.h progress.h gettext.h @ENABLE_REISER4_TRUE@partclone_reiser4_CFLAGS = -DREISER4 @ENABLE_REISER4_TRUE@partclone_reiser4_LDADD = -lreiser4 -laal @ENABLE_HFSP_TRUE@partclone_hfsp_SOURCES = main.c partclone.c progress.c hfsplusclone.c hfsplusclone.h partclone.h progress.h gettext.h @ENABLE_HFSP_TRUE@partclone_hfsp_CFLAGS = -DHFSPLUS @ENABLE_XFS_TRUE@partclone_xfs_SOURCES = main.c partclone.c progress.c xfsclone.c xfsclone.h partclone.h progress.h gettext.h $(XFS_SOURCE) @ENABLE_XFS_TRUE@partclone_xfs_CFLAGS = -DXFS -D_GNU_SOURCE -DNDEBUG $(UUID_CFLAGS) @ENABLE_XFS_TRUE@partclone_xfs_LDADD = -lrt -lpthread -luuid @ENABLE_EXFAT_TRUE@partclone_exfat_SOURCES = main.c partclone.c progress.c exfatclone.c exfatclone.h partclone.h progress.h gettext.h $(EXFATFS_SOURCE) @ENABLE_EXFAT_TRUE@partclone_exfat_CFLAGS = -DEXFAT -D_GNU_SOURCE -std=c99 @ENABLE_F2FS_TRUE@partclone_f2fs_SOURCES = main.c partclone.c progress.c f2fsclone.c f2fsclone.h partclone.h progress.h gettext.h $(F2FS_SOURCE) @ENABLE_F2FS_TRUE@partclone_f2fs_CFLAGS = -DF2FS @ENABLE_F2FS_TRUE@partclone_f2fs_LDADD = -luuid @ENABLE_NILFS2_TRUE@partclone_nilfs2_SOURCES = main.c partclone.c progress.c nilfsclone.c nilfsclone.h partclone.h progress.h gettext.h @ENABLE_NILFS2_TRUE@partclone_nilfs2_CFLAGS = -DNILFS @ENABLE_NILFS2_TRUE@partclone_nilfs2_LDADD = -lnilfs @ENABLE_FAT_TRUE@partclone_fat_SOURCES = main.c partclone.c progress.c fatclone.c fatclone.h partclone.h progress.h gettext.h @ENABLE_FAT_TRUE@partclone_fat_CFLAGS = -DFAT partclone_ntfsfixboot_SOURCES = ntfsfixboot.c @ENABLE_NTFS_TRUE@partclone_ntfs_SOURCES = main.c partclone.c progress.c ntfsclone-ng.c ntfsclone-ng.h partclone.h progress.h gettext.h @ENABLE_NTFS_3G_FALSE@@ENABLE_NTFS_TRUE@partclone_ntfs_CFLAGS = -DNTFS @ENABLE_NTFS_3G_TRUE@@ENABLE_NTFS_TRUE@partclone_ntfs_CFLAGS = -DNTFS3G @ENABLE_NTFS_3G_FALSE@@ENABLE_NTFS_TRUE@partclone_ntfs_LDADD = -lntfs @ENABLE_NTFS_3G_TRUE@@ENABLE_NTFS_TRUE@partclone_ntfs_LDADD = -lntfs-3g @ENABLE_UFS_TRUE@partclone_ufs_SOURCES = main.c partclone.c progress.c ufsclone.c ufsclone.h partclone.h progress.h gettext.h @ENABLE_UFS_TRUE@partclone_ufs_CFLAGS = -DUFS -D_GNU_SOURCE @ENABLE_UFS_TRUE@partclone_ufs_LDADD = -lufs -lbsd @ENABLE_VMFS_TRUE@partclone_vmfs_SOURCES = main.c partclone.c progress.c vmfsclone.c vmfsclone.h partclone.h progress.h gettext.h @ENABLE_VMFS_TRUE@partclone_vmfs_CFLAGS = -DVMFS -D_GNU_SOURCE $(UUID_CFLAGS) @ENABLE_VMFS_TRUE@partclone_vmfs_LDADD = -lvmfs -luuid @ENABLE_VMFS_TRUE@partclone_vmfs5_SOURCES = main.c partclone.c progress.c vmfs5clone.c vmfsclone.h partclone.h progress.h gettext.h @ENABLE_VMFS_TRUE@partclone_vmfs5_CFLAGS = -DVMFS -D_GNU_SOURCE $(UUID_CFLAGS) @ENABLE_VMFS_TRUE@partclone_vmfs5_LDADD = -lvmfs -luuid @ENABLE_VMFS_TRUE@partclone_fstype_SOURCES = fstype.c @ENABLE_VMFS_TRUE@partclone_fstype_CFLAGS = -DVMFS -D_GNU_SOURCE $(UUID_CFLAGS) @ENABLE_VMFS_TRUE@partclone_fstype_LDADD = -lvmfs -luuid #partclone_jfs_SOURCES=main.c partclone.c progress.c jfs_devices.c jfs_devices.h jfsclone.c jfsclone.h partclone.h progress.h gettext.h @ENABLE_JFS_TRUE@partclone_jfs_SOURCES = main.c partclone.c progress.c jfsclone.c jfsclone.h partclone.h progress.h gettext.h @ENABLE_JFS_TRUE@partclone_jfs_CFLAGS = -DJFS @ENABLE_JFS_TRUE@partclone_jfs_LDADD = -luuid -ljfs @ENABLE_BTRFS_TRUE@partclone_btrfs_SOURCES = main.c partclone.c progress.c btrfsclone.c btrfsclone.h partclone.h progress.h gettext.h $(BTRFS_SOURCE) @ENABLE_BTRFS_TRUE@partclone_btrfs_CFLAGS = -DBTRFS -DBTRFS_FLAT_INCLUDES @ENABLE_BTRFS_TRUE@partclone_btrfs_LDADD = -luuid -lblkid @ENABLE_MINIX_TRUE@partclone_minix_SOURCES = main.c partclone.c progress.c minixclone.c minixclone.h partclone.h progress.h gettext.h @ENABLE_MINIX_TRUE@partclone_minix_CFLAGS = -DMINIX all: all-am .SUFFIXES: .SUFFIXES: .c .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-sbinPROGRAMS: $(sbin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \ } \ ; done uninstall-sbinPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(sbindir)" && rm -f $$files clean-sbinPROGRAMS: -test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS) btrfs/$(am__dirstamp): @$(MKDIR_P) btrfs @: > btrfs/$(am__dirstamp) btrfs/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) btrfs/$(DEPDIR) @: > btrfs/$(DEPDIR)/$(am__dirstamp) btrfs/partclone_btrfs-extent_io.$(OBJEXT): btrfs/$(am__dirstamp) \ btrfs/$(DEPDIR)/$(am__dirstamp) btrfs/partclone_btrfs-inode-item.$(OBJEXT): btrfs/$(am__dirstamp) \ btrfs/$(DEPDIR)/$(am__dirstamp) btrfs/partclone_btrfs-radix-tree.$(OBJEXT): btrfs/$(am__dirstamp) \ btrfs/$(DEPDIR)/$(am__dirstamp) btrfs/partclone_btrfs-root-tree.$(OBJEXT): btrfs/$(am__dirstamp) \ btrfs/$(DEPDIR)/$(am__dirstamp) btrfs/partclone_btrfs-ulist.$(OBJEXT): btrfs/$(am__dirstamp) \ btrfs/$(DEPDIR)/$(am__dirstamp) btrfs/partclone_btrfs-volumes.$(OBJEXT): btrfs/$(am__dirstamp) \ btrfs/$(DEPDIR)/$(am__dirstamp) btrfs/partclone_btrfs-dir-item.$(OBJEXT): btrfs/$(am__dirstamp) \ btrfs/$(DEPDIR)/$(am__dirstamp) btrfs/partclone_btrfs-inode-map.$(OBJEXT): btrfs/$(am__dirstamp) \ btrfs/$(DEPDIR)/$(am__dirstamp) btrfs/partclone_btrfs-print-tree.$(OBJEXT): btrfs/$(am__dirstamp) \ btrfs/$(DEPDIR)/$(am__dirstamp) btrfs/partclone_btrfs-btrfs-list.$(OBJEXT): btrfs/$(am__dirstamp) \ btrfs/$(DEPDIR)/$(am__dirstamp) btrfs/partclone_btrfs-disk-io.$(OBJEXT): btrfs/$(am__dirstamp) \ btrfs/$(DEPDIR)/$(am__dirstamp) btrfs/partclone_btrfs-extent-tree.$(OBJEXT): btrfs/$(am__dirstamp) \ btrfs/$(DEPDIR)/$(am__dirstamp) btrfs/partclone_btrfs-raid6.$(OBJEXT): btrfs/$(am__dirstamp) \ btrfs/$(DEPDIR)/$(am__dirstamp) btrfs/partclone_btrfs-send-stream.$(OBJEXT): btrfs/$(am__dirstamp) \ btrfs/$(DEPDIR)/$(am__dirstamp) btrfs/partclone_btrfs-utils.$(OBJEXT): btrfs/$(am__dirstamp) \ btrfs/$(DEPDIR)/$(am__dirstamp) btrfs/partclone_btrfs-file-item.$(OBJEXT): btrfs/$(am__dirstamp) \ btrfs/$(DEPDIR)/$(am__dirstamp) btrfs/partclone_btrfs-qgroup.$(OBJEXT): btrfs/$(am__dirstamp) \ btrfs/$(DEPDIR)/$(am__dirstamp) btrfs/partclone_btrfs-rbtree.$(OBJEXT): btrfs/$(am__dirstamp) \ btrfs/$(DEPDIR)/$(am__dirstamp) btrfs/partclone_btrfs-crc32c.$(OBJEXT): btrfs/$(am__dirstamp) \ btrfs/$(DEPDIR)/$(am__dirstamp) btrfs/partclone_btrfs-free-space-cache.$(OBJEXT): \ btrfs/$(am__dirstamp) btrfs/$(DEPDIR)/$(am__dirstamp) btrfs/partclone_btrfs-send-utils.$(OBJEXT): btrfs/$(am__dirstamp) \ btrfs/$(DEPDIR)/$(am__dirstamp) btrfs/partclone_btrfs-utils-lib.$(OBJEXT): btrfs/$(am__dirstamp) \ btrfs/$(DEPDIR)/$(am__dirstamp) btrfs/partclone_btrfs-rbtree-utils.$(OBJEXT): btrfs/$(am__dirstamp) \ btrfs/$(DEPDIR)/$(am__dirstamp) btrfs/partclone_btrfs-extent-cache.$(OBJEXT): btrfs/$(am__dirstamp) \ btrfs/$(DEPDIR)/$(am__dirstamp) btrfs/partclone_btrfs-list_sort.$(OBJEXT): btrfs/$(am__dirstamp) \ btrfs/$(DEPDIR)/$(am__dirstamp) btrfs/partclone_btrfs-qgroup-verify.$(OBJEXT): btrfs/$(am__dirstamp) \ btrfs/$(DEPDIR)/$(am__dirstamp) btrfs/partclone_btrfs-repair.$(OBJEXT): btrfs/$(am__dirstamp) \ btrfs/$(DEPDIR)/$(am__dirstamp) btrfs/partclone_btrfs-uuid-tree.$(OBJEXT): btrfs/$(am__dirstamp) \ btrfs/$(DEPDIR)/$(am__dirstamp) btrfs/partclone_btrfs-ctree.$(OBJEXT): btrfs/$(am__dirstamp) \ btrfs/$(DEPDIR)/$(am__dirstamp) partclone.btrfs$(EXEEXT): $(partclone_btrfs_OBJECTS) $(partclone_btrfs_DEPENDENCIES) $(EXTRA_partclone_btrfs_DEPENDENCIES) @rm -f partclone.btrfs$(EXEEXT) $(AM_V_CCLD)$(partclone_btrfs_LINK) $(partclone_btrfs_OBJECTS) $(partclone_btrfs_LDADD) $(LIBS) partclone.chkimg$(EXEEXT): $(partclone_chkimg_OBJECTS) $(partclone_chkimg_DEPENDENCIES) $(EXTRA_partclone_chkimg_DEPENDENCIES) @rm -f partclone.chkimg$(EXEEXT) $(AM_V_CCLD)$(partclone_chkimg_LINK) $(partclone_chkimg_OBJECTS) $(partclone_chkimg_LDADD) $(LIBS) partclone.dd$(EXEEXT): $(partclone_dd_OBJECTS) $(partclone_dd_DEPENDENCIES) $(EXTRA_partclone_dd_DEPENDENCIES) @rm -f partclone.dd$(EXEEXT) $(AM_V_CCLD)$(partclone_dd_LINK) $(partclone_dd_OBJECTS) $(partclone_dd_LDADD) $(LIBS) exfat/$(am__dirstamp): @$(MKDIR_P) exfat @: > exfat/$(am__dirstamp) exfat/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) exfat/$(DEPDIR) @: > exfat/$(DEPDIR)/$(am__dirstamp) exfat/partclone_exfat-cluster.$(OBJEXT): exfat/$(am__dirstamp) \ exfat/$(DEPDIR)/$(am__dirstamp) exfat/partclone_exfat-utf.$(OBJEXT): exfat/$(am__dirstamp) \ exfat/$(DEPDIR)/$(am__dirstamp) exfat/partclone_exfat-utils.$(OBJEXT): exfat/$(am__dirstamp) \ exfat/$(DEPDIR)/$(am__dirstamp) exfat/partclone_exfat-lookup.$(OBJEXT): exfat/$(am__dirstamp) \ exfat/$(DEPDIR)/$(am__dirstamp) exfat/partclone_exfat-io.$(OBJEXT): exfat/$(am__dirstamp) \ exfat/$(DEPDIR)/$(am__dirstamp) exfat/partclone_exfat-log.$(OBJEXT): exfat/$(am__dirstamp) \ exfat/$(DEPDIR)/$(am__dirstamp) exfat/partclone_exfat-node.$(OBJEXT): exfat/$(am__dirstamp) \ exfat/$(DEPDIR)/$(am__dirstamp) exfat/partclone_exfat-mount.$(OBJEXT): exfat/$(am__dirstamp) \ exfat/$(DEPDIR)/$(am__dirstamp) exfat/partclone_exfat-time.$(OBJEXT): exfat/$(am__dirstamp) \ exfat/$(DEPDIR)/$(am__dirstamp) partclone.exfat$(EXEEXT): $(partclone_exfat_OBJECTS) $(partclone_exfat_DEPENDENCIES) $(EXTRA_partclone_exfat_DEPENDENCIES) @rm -f partclone.exfat$(EXEEXT) $(AM_V_CCLD)$(partclone_exfat_LINK) $(partclone_exfat_OBJECTS) $(partclone_exfat_LDADD) $(LIBS) partclone.extfs$(EXEEXT): $(partclone_extfs_OBJECTS) $(partclone_extfs_DEPENDENCIES) $(EXTRA_partclone_extfs_DEPENDENCIES) @rm -f partclone.extfs$(EXEEXT) $(AM_V_CCLD)$(partclone_extfs_LINK) $(partclone_extfs_OBJECTS) $(partclone_extfs_LDADD) $(LIBS) f2fs/$(am__dirstamp): @$(MKDIR_P) f2fs @: > f2fs/$(am__dirstamp) f2fs/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) f2fs/$(DEPDIR) @: > f2fs/$(DEPDIR)/$(am__dirstamp) f2fs/partclone_f2fs-fsck.$(OBJEXT): f2fs/$(am__dirstamp) \ f2fs/$(DEPDIR)/$(am__dirstamp) f2fs/partclone_f2fs-libf2fs.$(OBJEXT): f2fs/$(am__dirstamp) \ f2fs/$(DEPDIR)/$(am__dirstamp) f2fs/partclone_f2fs-mount.$(OBJEXT): f2fs/$(am__dirstamp) \ f2fs/$(DEPDIR)/$(am__dirstamp) partclone.f2fs$(EXEEXT): $(partclone_f2fs_OBJECTS) $(partclone_f2fs_DEPENDENCIES) $(EXTRA_partclone_f2fs_DEPENDENCIES) @rm -f partclone.f2fs$(EXEEXT) $(AM_V_CCLD)$(partclone_f2fs_LINK) $(partclone_f2fs_OBJECTS) $(partclone_f2fs_LDADD) $(LIBS) partclone.fat$(EXEEXT): $(partclone_fat_OBJECTS) $(partclone_fat_DEPENDENCIES) $(EXTRA_partclone_fat_DEPENDENCIES) @rm -f partclone.fat$(EXEEXT) $(AM_V_CCLD)$(partclone_fat_LINK) $(partclone_fat_OBJECTS) $(partclone_fat_LDADD) $(LIBS) partclone.fstype$(EXEEXT): $(partclone_fstype_OBJECTS) $(partclone_fstype_DEPENDENCIES) $(EXTRA_partclone_fstype_DEPENDENCIES) @rm -f partclone.fstype$(EXEEXT) $(AM_V_CCLD)$(partclone_fstype_LINK) $(partclone_fstype_OBJECTS) $(partclone_fstype_LDADD) $(LIBS) partclone.hfsp$(EXEEXT): $(partclone_hfsp_OBJECTS) $(partclone_hfsp_DEPENDENCIES) $(EXTRA_partclone_hfsp_DEPENDENCIES) @rm -f partclone.hfsp$(EXEEXT) $(AM_V_CCLD)$(partclone_hfsp_LINK) $(partclone_hfsp_OBJECTS) $(partclone_hfsp_LDADD) $(LIBS) partclone.imager$(EXEEXT): $(partclone_imager_OBJECTS) $(partclone_imager_DEPENDENCIES) $(EXTRA_partclone_imager_DEPENDENCIES) @rm -f partclone.imager$(EXEEXT) $(AM_V_CCLD)$(partclone_imager_LINK) $(partclone_imager_OBJECTS) $(partclone_imager_LDADD) $(LIBS) partclone.info$(EXEEXT): $(partclone_info_OBJECTS) $(partclone_info_DEPENDENCIES) $(EXTRA_partclone_info_DEPENDENCIES) @rm -f partclone.info$(EXEEXT) $(AM_V_CCLD)$(LINK) $(partclone_info_OBJECTS) $(partclone_info_LDADD) $(LIBS) partclone.jfs$(EXEEXT): $(partclone_jfs_OBJECTS) $(partclone_jfs_DEPENDENCIES) $(EXTRA_partclone_jfs_DEPENDENCIES) @rm -f partclone.jfs$(EXEEXT) $(AM_V_CCLD)$(partclone_jfs_LINK) $(partclone_jfs_OBJECTS) $(partclone_jfs_LDADD) $(LIBS) partclone.minix$(EXEEXT): $(partclone_minix_OBJECTS) $(partclone_minix_DEPENDENCIES) $(EXTRA_partclone_minix_DEPENDENCIES) @rm -f partclone.minix$(EXEEXT) $(AM_V_CCLD)$(partclone_minix_LINK) $(partclone_minix_OBJECTS) $(partclone_minix_LDADD) $(LIBS) partclone.nilfs2$(EXEEXT): $(partclone_nilfs2_OBJECTS) $(partclone_nilfs2_DEPENDENCIES) $(EXTRA_partclone_nilfs2_DEPENDENCIES) @rm -f partclone.nilfs2$(EXEEXT) $(AM_V_CCLD)$(partclone_nilfs2_LINK) $(partclone_nilfs2_OBJECTS) $(partclone_nilfs2_LDADD) $(LIBS) partclone.ntfs$(EXEEXT): $(partclone_ntfs_OBJECTS) $(partclone_ntfs_DEPENDENCIES) $(EXTRA_partclone_ntfs_DEPENDENCIES) @rm -f partclone.ntfs$(EXEEXT) $(AM_V_CCLD)$(partclone_ntfs_LINK) $(partclone_ntfs_OBJECTS) $(partclone_ntfs_LDADD) $(LIBS) partclone.ntfsfixboot$(EXEEXT): $(partclone_ntfsfixboot_OBJECTS) $(partclone_ntfsfixboot_DEPENDENCIES) $(EXTRA_partclone_ntfsfixboot_DEPENDENCIES) @rm -f partclone.ntfsfixboot$(EXEEXT) $(AM_V_CCLD)$(LINK) $(partclone_ntfsfixboot_OBJECTS) $(partclone_ntfsfixboot_LDADD) $(LIBS) partclone.reiser4$(EXEEXT): $(partclone_reiser4_OBJECTS) $(partclone_reiser4_DEPENDENCIES) $(EXTRA_partclone_reiser4_DEPENDENCIES) @rm -f partclone.reiser4$(EXEEXT) $(AM_V_CCLD)$(partclone_reiser4_LINK) $(partclone_reiser4_OBJECTS) $(partclone_reiser4_LDADD) $(LIBS) partclone.reiserfs$(EXEEXT): $(partclone_reiserfs_OBJECTS) $(partclone_reiserfs_DEPENDENCIES) $(EXTRA_partclone_reiserfs_DEPENDENCIES) @rm -f partclone.reiserfs$(EXEEXT) $(AM_V_CCLD)$(partclone_reiserfs_LINK) $(partclone_reiserfs_OBJECTS) $(partclone_reiserfs_LDADD) $(LIBS) partclone.restore$(EXEEXT): $(partclone_restore_OBJECTS) $(partclone_restore_DEPENDENCIES) $(EXTRA_partclone_restore_DEPENDENCIES) @rm -f partclone.restore$(EXEEXT) $(AM_V_CCLD)$(partclone_restore_LINK) $(partclone_restore_OBJECTS) $(partclone_restore_LDADD) $(LIBS) partclone.ufs$(EXEEXT): $(partclone_ufs_OBJECTS) $(partclone_ufs_DEPENDENCIES) $(EXTRA_partclone_ufs_DEPENDENCIES) @rm -f partclone.ufs$(EXEEXT) $(AM_V_CCLD)$(partclone_ufs_LINK) $(partclone_ufs_OBJECTS) $(partclone_ufs_LDADD) $(LIBS) partclone.vmfs$(EXEEXT): $(partclone_vmfs_OBJECTS) $(partclone_vmfs_DEPENDENCIES) $(EXTRA_partclone_vmfs_DEPENDENCIES) @rm -f partclone.vmfs$(EXEEXT) $(AM_V_CCLD)$(partclone_vmfs_LINK) $(partclone_vmfs_OBJECTS) $(partclone_vmfs_LDADD) $(LIBS) partclone.vmfs5$(EXEEXT): $(partclone_vmfs5_OBJECTS) $(partclone_vmfs5_DEPENDENCIES) $(EXTRA_partclone_vmfs5_DEPENDENCIES) @rm -f partclone.vmfs5$(EXEEXT) $(AM_V_CCLD)$(partclone_vmfs5_LINK) $(partclone_vmfs5_OBJECTS) $(partclone_vmfs5_LDADD) $(LIBS) xfs/$(am__dirstamp): @$(MKDIR_P) xfs @: > xfs/$(am__dirstamp) xfs/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) xfs/$(DEPDIR) @: > xfs/$(DEPDIR)/$(am__dirstamp) xfs/partclone_xfs-xfs_attr.$(OBJEXT): xfs/$(am__dirstamp) \ xfs/$(DEPDIR)/$(am__dirstamp) xfs/partclone_xfs-xfs_dir2_block.$(OBJEXT): xfs/$(am__dirstamp) \ xfs/$(DEPDIR)/$(am__dirstamp) xfs/partclone_xfs-cache.$(OBJEXT): xfs/$(am__dirstamp) \ xfs/$(DEPDIR)/$(am__dirstamp) xfs/partclone_xfs-linux.$(OBJEXT): xfs/$(am__dirstamp) \ xfs/$(DEPDIR)/$(am__dirstamp) xfs/partclone_xfs-xfs_attr_leaf.$(OBJEXT): xfs/$(am__dirstamp) \ xfs/$(DEPDIR)/$(am__dirstamp) xfs/partclone_xfs-xfs_dir2.$(OBJEXT): xfs/$(am__dirstamp) \ xfs/$(DEPDIR)/$(am__dirstamp) xfs/partclone_xfs-xfs_dir2_data.$(OBJEXT): xfs/$(am__dirstamp) \ xfs/$(DEPDIR)/$(am__dirstamp) xfs/partclone_xfs-xfs_attr_remote.$(OBJEXT): xfs/$(am__dirstamp) \ xfs/$(DEPDIR)/$(am__dirstamp) xfs/partclone_xfs-xfs_log_rlimit.$(OBJEXT): xfs/$(am__dirstamp) \ xfs/$(DEPDIR)/$(am__dirstamp) xfs/partclone_xfs-crc32.$(OBJEXT): xfs/$(am__dirstamp) \ xfs/$(DEPDIR)/$(am__dirstamp) xfs/partclone_xfs-logitem.$(OBJEXT): xfs/$(am__dirstamp) \ xfs/$(DEPDIR)/$(am__dirstamp) xfs/partclone_xfs-xfs_dir2_leaf.$(OBJEXT): xfs/$(am__dirstamp) \ xfs/$(DEPDIR)/$(am__dirstamp) xfs/partclone_xfs-xfs_dir2_node.$(OBJEXT): xfs/$(am__dirstamp) \ xfs/$(DEPDIR)/$(am__dirstamp) xfs/partclone_xfs-xfs_bit.$(OBJEXT): xfs/$(am__dirstamp) \ xfs/$(DEPDIR)/$(am__dirstamp) xfs/partclone_xfs-xfs_dir2_sf.$(OBJEXT): xfs/$(am__dirstamp) \ xfs/$(DEPDIR)/$(am__dirstamp) xfs/partclone_xfs-xfs_rtbitmap.$(OBJEXT): xfs/$(am__dirstamp) \ xfs/$(DEPDIR)/$(am__dirstamp) xfs/partclone_xfs-xfs_bmap_btree.$(OBJEXT): xfs/$(am__dirstamp) \ xfs/$(DEPDIR)/$(am__dirstamp) xfs/partclone_xfs-xfs_dquot_buf.$(OBJEXT): xfs/$(am__dirstamp) \ xfs/$(DEPDIR)/$(am__dirstamp) xfs/partclone_xfs-xfs_sb.$(OBJEXT): xfs/$(am__dirstamp) \ xfs/$(DEPDIR)/$(am__dirstamp) xfs/partclone_xfs-init.$(OBJEXT): xfs/$(am__dirstamp) \ xfs/$(DEPDIR)/$(am__dirstamp) xfs/partclone_xfs-radix-tree.$(OBJEXT): xfs/$(am__dirstamp) \ xfs/$(DEPDIR)/$(am__dirstamp) xfs/partclone_xfs-xfs_bmap.$(OBJEXT): xfs/$(am__dirstamp) \ xfs/$(DEPDIR)/$(am__dirstamp) xfs/partclone_xfs-xfs_symlink_remote.$(OBJEXT): xfs/$(am__dirstamp) \ xfs/$(DEPDIR)/$(am__dirstamp) xfs/partclone_xfs-rdwr.$(OBJEXT): xfs/$(am__dirstamp) \ xfs/$(DEPDIR)/$(am__dirstamp) xfs/partclone_xfs-xfs_btree.$(OBJEXT): xfs/$(am__dirstamp) \ xfs/$(DEPDIR)/$(am__dirstamp) xfs/partclone_xfs-xfs_ialloc_btree.$(OBJEXT): xfs/$(am__dirstamp) \ xfs/$(DEPDIR)/$(am__dirstamp) xfs/partclone_xfs-trans.$(OBJEXT): xfs/$(am__dirstamp) \ xfs/$(DEPDIR)/$(am__dirstamp) xfs/partclone_xfs-kmem.$(OBJEXT): xfs/$(am__dirstamp) \ xfs/$(DEPDIR)/$(am__dirstamp) xfs/partclone_xfs-util.$(OBJEXT): xfs/$(am__dirstamp) \ xfs/$(DEPDIR)/$(am__dirstamp) xfs/partclone_xfs-xfs_ialloc.$(OBJEXT): xfs/$(am__dirstamp) \ xfs/$(DEPDIR)/$(am__dirstamp) xfs/partclone_xfs-xfs_trans_resv.$(OBJEXT): xfs/$(am__dirstamp) \ xfs/$(DEPDIR)/$(am__dirstamp) xfs/partclone_xfs-xfs_alloc_btree.$(OBJEXT): xfs/$(am__dirstamp) \ xfs/$(DEPDIR)/$(am__dirstamp) xfs/partclone_xfs-xfs_da_btree.$(OBJEXT): xfs/$(am__dirstamp) \ xfs/$(DEPDIR)/$(am__dirstamp) xfs/partclone_xfs-xfs_inode_buf.$(OBJEXT): xfs/$(am__dirstamp) \ xfs/$(DEPDIR)/$(am__dirstamp) xfs/partclone_xfs-xfs_alloc.$(OBJEXT): xfs/$(am__dirstamp) \ xfs/$(DEPDIR)/$(am__dirstamp) xfs/partclone_xfs-xfs_da_format.$(OBJEXT): xfs/$(am__dirstamp) \ xfs/$(DEPDIR)/$(am__dirstamp) xfs/partclone_xfs-xfs_inode_fork.$(OBJEXT): xfs/$(am__dirstamp) \ xfs/$(DEPDIR)/$(am__dirstamp) partclone.xfs$(EXEEXT): $(partclone_xfs_OBJECTS) $(partclone_xfs_DEPENDENCIES) $(EXTRA_partclone_xfs_DEPENDENCIES) @rm -f partclone.xfs$(EXEEXT) $(AM_V_CCLD)$(partclone_xfs_LINK) $(partclone_xfs_OBJECTS) $(partclone_xfs_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) -rm -f btrfs/*.$(OBJEXT) -rm -f exfat/*.$(OBJEXT) -rm -f f2fs/*.$(OBJEXT) -rm -f xfs/*.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/info.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntfsfixboot.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_btrfs-btrfsclone.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_btrfs-main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_btrfs-partclone.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_btrfs-progress.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_chkimg-ddclone.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_chkimg-main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_chkimg-partclone.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_chkimg-progress.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_dd-ddclone.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_dd-main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_dd-partclone.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_dd-progress.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_exfat-exfatclone.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_exfat-main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_exfat-partclone.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_exfat-progress.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_extfs-extfsclone.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_extfs-main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_extfs-partclone.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_extfs-progress.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_f2fs-f2fsclone.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_f2fs-main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_f2fs-partclone.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_f2fs-progress.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_fat-fatclone.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_fat-main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_fat-partclone.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_fat-progress.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_fstype-fstype.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_hfsp-hfsplusclone.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_hfsp-main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_hfsp-partclone.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_hfsp-progress.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_imager-ddclone.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_imager-main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_imager-partclone.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_imager-progress.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_jfs-jfsclone.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_jfs-main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_jfs-partclone.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_jfs-progress.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_minix-main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_minix-minixclone.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_minix-partclone.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_minix-progress.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_nilfs2-main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_nilfs2-nilfsclone.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_nilfs2-partclone.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_nilfs2-progress.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_ntfs-main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_ntfs-ntfsclone-ng.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_ntfs-partclone.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_ntfs-progress.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_reiser4-main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_reiser4-partclone.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_reiser4-progress.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_reiser4-reiser4clone.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_reiserfs-main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_reiserfs-partclone.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_reiserfs-progress.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_reiserfs-reiserfsclone.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_restore-ddclone.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_restore-main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_restore-partclone.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_restore-progress.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_ufs-main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_ufs-partclone.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_ufs-progress.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_ufs-ufsclone.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_vmfs-main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_vmfs-partclone.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_vmfs-progress.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_vmfs-vmfsclone.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_vmfs5-main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_vmfs5-partclone.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_vmfs5-progress.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_vmfs5-vmfs5clone.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_xfs-main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_xfs-partclone.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_xfs-progress.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partclone_xfs-xfsclone.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@btrfs/$(DEPDIR)/partclone_btrfs-btrfs-list.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@btrfs/$(DEPDIR)/partclone_btrfs-crc32c.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@btrfs/$(DEPDIR)/partclone_btrfs-ctree.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@btrfs/$(DEPDIR)/partclone_btrfs-dir-item.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@btrfs/$(DEPDIR)/partclone_btrfs-disk-io.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@btrfs/$(DEPDIR)/partclone_btrfs-extent-cache.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@btrfs/$(DEPDIR)/partclone_btrfs-extent-tree.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@btrfs/$(DEPDIR)/partclone_btrfs-extent_io.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@btrfs/$(DEPDIR)/partclone_btrfs-file-item.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@btrfs/$(DEPDIR)/partclone_btrfs-free-space-cache.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@btrfs/$(DEPDIR)/partclone_btrfs-inode-item.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@btrfs/$(DEPDIR)/partclone_btrfs-inode-map.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@btrfs/$(DEPDIR)/partclone_btrfs-list_sort.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@btrfs/$(DEPDIR)/partclone_btrfs-print-tree.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@btrfs/$(DEPDIR)/partclone_btrfs-qgroup-verify.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@btrfs/$(DEPDIR)/partclone_btrfs-qgroup.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@btrfs/$(DEPDIR)/partclone_btrfs-radix-tree.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@btrfs/$(DEPDIR)/partclone_btrfs-raid6.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@btrfs/$(DEPDIR)/partclone_btrfs-rbtree-utils.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@btrfs/$(DEPDIR)/partclone_btrfs-rbtree.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@btrfs/$(DEPDIR)/partclone_btrfs-repair.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@btrfs/$(DEPDIR)/partclone_btrfs-root-tree.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@btrfs/$(DEPDIR)/partclone_btrfs-send-stream.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@btrfs/$(DEPDIR)/partclone_btrfs-send-utils.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@btrfs/$(DEPDIR)/partclone_btrfs-ulist.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@btrfs/$(DEPDIR)/partclone_btrfs-utils-lib.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@btrfs/$(DEPDIR)/partclone_btrfs-utils.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@btrfs/$(DEPDIR)/partclone_btrfs-uuid-tree.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@btrfs/$(DEPDIR)/partclone_btrfs-volumes.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@exfat/$(DEPDIR)/partclone_exfat-cluster.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@exfat/$(DEPDIR)/partclone_exfat-io.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@exfat/$(DEPDIR)/partclone_exfat-log.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@exfat/$(DEPDIR)/partclone_exfat-lookup.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@exfat/$(DEPDIR)/partclone_exfat-mount.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@exfat/$(DEPDIR)/partclone_exfat-node.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@exfat/$(DEPDIR)/partclone_exfat-time.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@exfat/$(DEPDIR)/partclone_exfat-utf.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@exfat/$(DEPDIR)/partclone_exfat-utils.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@f2fs/$(DEPDIR)/partclone_f2fs-fsck.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@f2fs/$(DEPDIR)/partclone_f2fs-libf2fs.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@f2fs/$(DEPDIR)/partclone_f2fs-mount.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@xfs/$(DEPDIR)/partclone_xfs-cache.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@xfs/$(DEPDIR)/partclone_xfs-crc32.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@xfs/$(DEPDIR)/partclone_xfs-init.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@xfs/$(DEPDIR)/partclone_xfs-kmem.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@xfs/$(DEPDIR)/partclone_xfs-linux.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@xfs/$(DEPDIR)/partclone_xfs-logitem.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@xfs/$(DEPDIR)/partclone_xfs-radix-tree.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@xfs/$(DEPDIR)/partclone_xfs-rdwr.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@xfs/$(DEPDIR)/partclone_xfs-trans.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@xfs/$(DEPDIR)/partclone_xfs-util.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@xfs/$(DEPDIR)/partclone_xfs-xfs_alloc.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@xfs/$(DEPDIR)/partclone_xfs-xfs_alloc_btree.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@xfs/$(DEPDIR)/partclone_xfs-xfs_attr.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@xfs/$(DEPDIR)/partclone_xfs-xfs_attr_leaf.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@xfs/$(DEPDIR)/partclone_xfs-xfs_attr_remote.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@xfs/$(DEPDIR)/partclone_xfs-xfs_bit.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@xfs/$(DEPDIR)/partclone_xfs-xfs_bmap.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@xfs/$(DEPDIR)/partclone_xfs-xfs_bmap_btree.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@xfs/$(DEPDIR)/partclone_xfs-xfs_btree.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@xfs/$(DEPDIR)/partclone_xfs-xfs_da_btree.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@xfs/$(DEPDIR)/partclone_xfs-xfs_da_format.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@xfs/$(DEPDIR)/partclone_xfs-xfs_dir2.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@xfs/$(DEPDIR)/partclone_xfs-xfs_dir2_block.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@xfs/$(DEPDIR)/partclone_xfs-xfs_dir2_data.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@xfs/$(DEPDIR)/partclone_xfs-xfs_dir2_leaf.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@xfs/$(DEPDIR)/partclone_xfs-xfs_dir2_node.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@xfs/$(DEPDIR)/partclone_xfs-xfs_dir2_sf.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@xfs/$(DEPDIR)/partclone_xfs-xfs_dquot_buf.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@xfs/$(DEPDIR)/partclone_xfs-xfs_ialloc.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@xfs/$(DEPDIR)/partclone_xfs-xfs_ialloc_btree.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@xfs/$(DEPDIR)/partclone_xfs-xfs_inode_buf.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@xfs/$(DEPDIR)/partclone_xfs-xfs_inode_fork.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@xfs/$(DEPDIR)/partclone_xfs-xfs_log_rlimit.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@xfs/$(DEPDIR)/partclone_xfs-xfs_rtbitmap.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@xfs/$(DEPDIR)/partclone_xfs-xfs_sb.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@xfs/$(DEPDIR)/partclone_xfs-xfs_symlink_remote.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@xfs/$(DEPDIR)/partclone_xfs-xfs_trans_resv.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` partclone_btrfs-main.o: main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -MT partclone_btrfs-main.o -MD -MP -MF $(DEPDIR)/partclone_btrfs-main.Tpo -c -o partclone_btrfs-main.o `test -f 'main.c' || echo '$(srcdir)/'`main.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_btrfs-main.Tpo $(DEPDIR)/partclone_btrfs-main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='main.c' object='partclone_btrfs-main.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -c -o partclone_btrfs-main.o `test -f 'main.c' || echo '$(srcdir)/'`main.c partclone_btrfs-main.obj: main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -MT partclone_btrfs-main.obj -MD -MP -MF $(DEPDIR)/partclone_btrfs-main.Tpo -c -o partclone_btrfs-main.obj `if test -f 'main.c'; then $(CYGPATH_W) 'main.c'; else $(CYGPATH_W) '$(srcdir)/main.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_btrfs-main.Tpo $(DEPDIR)/partclone_btrfs-main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='main.c' object='partclone_btrfs-main.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -c -o partclone_btrfs-main.obj `if test -f 'main.c'; then $(CYGPATH_W) 'main.c'; else $(CYGPATH_W) '$(srcdir)/main.c'; fi` partclone_btrfs-partclone.o: partclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -MT partclone_btrfs-partclone.o -MD -MP -MF $(DEPDIR)/partclone_btrfs-partclone.Tpo -c -o partclone_btrfs-partclone.o `test -f 'partclone.c' || echo '$(srcdir)/'`partclone.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_btrfs-partclone.Tpo $(DEPDIR)/partclone_btrfs-partclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='partclone.c' object='partclone_btrfs-partclone.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -c -o partclone_btrfs-partclone.o `test -f 'partclone.c' || echo '$(srcdir)/'`partclone.c partclone_btrfs-partclone.obj: partclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -MT partclone_btrfs-partclone.obj -MD -MP -MF $(DEPDIR)/partclone_btrfs-partclone.Tpo -c -o partclone_btrfs-partclone.obj `if test -f 'partclone.c'; then $(CYGPATH_W) 'partclone.c'; else $(CYGPATH_W) '$(srcdir)/partclone.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_btrfs-partclone.Tpo $(DEPDIR)/partclone_btrfs-partclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='partclone.c' object='partclone_btrfs-partclone.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -c -o partclone_btrfs-partclone.obj `if test -f 'partclone.c'; then $(CYGPATH_W) 'partclone.c'; else $(CYGPATH_W) '$(srcdir)/partclone.c'; fi` partclone_btrfs-progress.o: progress.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -MT partclone_btrfs-progress.o -MD -MP -MF $(DEPDIR)/partclone_btrfs-progress.Tpo -c -o partclone_btrfs-progress.o `test -f 'progress.c' || echo '$(srcdir)/'`progress.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_btrfs-progress.Tpo $(DEPDIR)/partclone_btrfs-progress.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='progress.c' object='partclone_btrfs-progress.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -c -o partclone_btrfs-progress.o `test -f 'progress.c' || echo '$(srcdir)/'`progress.c partclone_btrfs-progress.obj: progress.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -MT partclone_btrfs-progress.obj -MD -MP -MF $(DEPDIR)/partclone_btrfs-progress.Tpo -c -o partclone_btrfs-progress.obj `if test -f 'progress.c'; then $(CYGPATH_W) 'progress.c'; else $(CYGPATH_W) '$(srcdir)/progress.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_btrfs-progress.Tpo $(DEPDIR)/partclone_btrfs-progress.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='progress.c' object='partclone_btrfs-progress.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -c -o partclone_btrfs-progress.obj `if test -f 'progress.c'; then $(CYGPATH_W) 'progress.c'; else $(CYGPATH_W) '$(srcdir)/progress.c'; fi` partclone_btrfs-btrfsclone.o: btrfsclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -MT partclone_btrfs-btrfsclone.o -MD -MP -MF $(DEPDIR)/partclone_btrfs-btrfsclone.Tpo -c -o partclone_btrfs-btrfsclone.o `test -f 'btrfsclone.c' || echo '$(srcdir)/'`btrfsclone.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_btrfs-btrfsclone.Tpo $(DEPDIR)/partclone_btrfs-btrfsclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btrfsclone.c' object='partclone_btrfs-btrfsclone.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -c -o partclone_btrfs-btrfsclone.o `test -f 'btrfsclone.c' || echo '$(srcdir)/'`btrfsclone.c partclone_btrfs-btrfsclone.obj: btrfsclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -MT partclone_btrfs-btrfsclone.obj -MD -MP -MF $(DEPDIR)/partclone_btrfs-btrfsclone.Tpo -c -o partclone_btrfs-btrfsclone.obj `if test -f 'btrfsclone.c'; then $(CYGPATH_W) 'btrfsclone.c'; else $(CYGPATH_W) '$(srcdir)/btrfsclone.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_btrfs-btrfsclone.Tpo $(DEPDIR)/partclone_btrfs-btrfsclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btrfsclone.c' object='partclone_btrfs-btrfsclone.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -c -o partclone_btrfs-btrfsclone.obj `if test -f 'btrfsclone.c'; then $(CYGPATH_W) 'btrfsclone.c'; else $(CYGPATH_W) '$(srcdir)/btrfsclone.c'; fi` btrfs/partclone_btrfs-extent_io.o: btrfs/extent_io.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -MT btrfs/partclone_btrfs-extent_io.o -MD -MP -MF btrfs/$(DEPDIR)/partclone_btrfs-extent_io.Tpo -c -o btrfs/partclone_btrfs-extent_io.o `test -f 'btrfs/extent_io.c' || echo '$(srcdir)/'`btrfs/extent_io.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) btrfs/$(DEPDIR)/partclone_btrfs-extent_io.Tpo btrfs/$(DEPDIR)/partclone_btrfs-extent_io.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btrfs/extent_io.c' object='btrfs/partclone_btrfs-extent_io.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -c -o btrfs/partclone_btrfs-extent_io.o `test -f 'btrfs/extent_io.c' || echo '$(srcdir)/'`btrfs/extent_io.c btrfs/partclone_btrfs-extent_io.obj: btrfs/extent_io.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -MT btrfs/partclone_btrfs-extent_io.obj -MD -MP -MF btrfs/$(DEPDIR)/partclone_btrfs-extent_io.Tpo -c -o btrfs/partclone_btrfs-extent_io.obj `if test -f 'btrfs/extent_io.c'; then $(CYGPATH_W) 'btrfs/extent_io.c'; else $(CYGPATH_W) '$(srcdir)/btrfs/extent_io.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) btrfs/$(DEPDIR)/partclone_btrfs-extent_io.Tpo btrfs/$(DEPDIR)/partclone_btrfs-extent_io.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btrfs/extent_io.c' object='btrfs/partclone_btrfs-extent_io.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -c -o btrfs/partclone_btrfs-extent_io.obj `if test -f 'btrfs/extent_io.c'; then $(CYGPATH_W) 'btrfs/extent_io.c'; else $(CYGPATH_W) '$(srcdir)/btrfs/extent_io.c'; fi` btrfs/partclone_btrfs-inode-item.o: btrfs/inode-item.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -MT btrfs/partclone_btrfs-inode-item.o -MD -MP -MF btrfs/$(DEPDIR)/partclone_btrfs-inode-item.Tpo -c -o btrfs/partclone_btrfs-inode-item.o `test -f 'btrfs/inode-item.c' || echo '$(srcdir)/'`btrfs/inode-item.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) btrfs/$(DEPDIR)/partclone_btrfs-inode-item.Tpo btrfs/$(DEPDIR)/partclone_btrfs-inode-item.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btrfs/inode-item.c' object='btrfs/partclone_btrfs-inode-item.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -c -o btrfs/partclone_btrfs-inode-item.o `test -f 'btrfs/inode-item.c' || echo '$(srcdir)/'`btrfs/inode-item.c btrfs/partclone_btrfs-inode-item.obj: btrfs/inode-item.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -MT btrfs/partclone_btrfs-inode-item.obj -MD -MP -MF btrfs/$(DEPDIR)/partclone_btrfs-inode-item.Tpo -c -o btrfs/partclone_btrfs-inode-item.obj `if test -f 'btrfs/inode-item.c'; then $(CYGPATH_W) 'btrfs/inode-item.c'; else $(CYGPATH_W) '$(srcdir)/btrfs/inode-item.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) btrfs/$(DEPDIR)/partclone_btrfs-inode-item.Tpo btrfs/$(DEPDIR)/partclone_btrfs-inode-item.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btrfs/inode-item.c' object='btrfs/partclone_btrfs-inode-item.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -c -o btrfs/partclone_btrfs-inode-item.obj `if test -f 'btrfs/inode-item.c'; then $(CYGPATH_W) 'btrfs/inode-item.c'; else $(CYGPATH_W) '$(srcdir)/btrfs/inode-item.c'; fi` btrfs/partclone_btrfs-radix-tree.o: btrfs/radix-tree.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -MT btrfs/partclone_btrfs-radix-tree.o -MD -MP -MF btrfs/$(DEPDIR)/partclone_btrfs-radix-tree.Tpo -c -o btrfs/partclone_btrfs-radix-tree.o `test -f 'btrfs/radix-tree.c' || echo '$(srcdir)/'`btrfs/radix-tree.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) btrfs/$(DEPDIR)/partclone_btrfs-radix-tree.Tpo btrfs/$(DEPDIR)/partclone_btrfs-radix-tree.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btrfs/radix-tree.c' object='btrfs/partclone_btrfs-radix-tree.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -c -o btrfs/partclone_btrfs-radix-tree.o `test -f 'btrfs/radix-tree.c' || echo '$(srcdir)/'`btrfs/radix-tree.c btrfs/partclone_btrfs-radix-tree.obj: btrfs/radix-tree.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -MT btrfs/partclone_btrfs-radix-tree.obj -MD -MP -MF btrfs/$(DEPDIR)/partclone_btrfs-radix-tree.Tpo -c -o btrfs/partclone_btrfs-radix-tree.obj `if test -f 'btrfs/radix-tree.c'; then $(CYGPATH_W) 'btrfs/radix-tree.c'; else $(CYGPATH_W) '$(srcdir)/btrfs/radix-tree.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) btrfs/$(DEPDIR)/partclone_btrfs-radix-tree.Tpo btrfs/$(DEPDIR)/partclone_btrfs-radix-tree.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btrfs/radix-tree.c' object='btrfs/partclone_btrfs-radix-tree.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -c -o btrfs/partclone_btrfs-radix-tree.obj `if test -f 'btrfs/radix-tree.c'; then $(CYGPATH_W) 'btrfs/radix-tree.c'; else $(CYGPATH_W) '$(srcdir)/btrfs/radix-tree.c'; fi` btrfs/partclone_btrfs-root-tree.o: btrfs/root-tree.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -MT btrfs/partclone_btrfs-root-tree.o -MD -MP -MF btrfs/$(DEPDIR)/partclone_btrfs-root-tree.Tpo -c -o btrfs/partclone_btrfs-root-tree.o `test -f 'btrfs/root-tree.c' || echo '$(srcdir)/'`btrfs/root-tree.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) btrfs/$(DEPDIR)/partclone_btrfs-root-tree.Tpo btrfs/$(DEPDIR)/partclone_btrfs-root-tree.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btrfs/root-tree.c' object='btrfs/partclone_btrfs-root-tree.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -c -o btrfs/partclone_btrfs-root-tree.o `test -f 'btrfs/root-tree.c' || echo '$(srcdir)/'`btrfs/root-tree.c btrfs/partclone_btrfs-root-tree.obj: btrfs/root-tree.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -MT btrfs/partclone_btrfs-root-tree.obj -MD -MP -MF btrfs/$(DEPDIR)/partclone_btrfs-root-tree.Tpo -c -o btrfs/partclone_btrfs-root-tree.obj `if test -f 'btrfs/root-tree.c'; then $(CYGPATH_W) 'btrfs/root-tree.c'; else $(CYGPATH_W) '$(srcdir)/btrfs/root-tree.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) btrfs/$(DEPDIR)/partclone_btrfs-root-tree.Tpo btrfs/$(DEPDIR)/partclone_btrfs-root-tree.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btrfs/root-tree.c' object='btrfs/partclone_btrfs-root-tree.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -c -o btrfs/partclone_btrfs-root-tree.obj `if test -f 'btrfs/root-tree.c'; then $(CYGPATH_W) 'btrfs/root-tree.c'; else $(CYGPATH_W) '$(srcdir)/btrfs/root-tree.c'; fi` btrfs/partclone_btrfs-ulist.o: btrfs/ulist.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -MT btrfs/partclone_btrfs-ulist.o -MD -MP -MF btrfs/$(DEPDIR)/partclone_btrfs-ulist.Tpo -c -o btrfs/partclone_btrfs-ulist.o `test -f 'btrfs/ulist.c' || echo '$(srcdir)/'`btrfs/ulist.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) btrfs/$(DEPDIR)/partclone_btrfs-ulist.Tpo btrfs/$(DEPDIR)/partclone_btrfs-ulist.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btrfs/ulist.c' object='btrfs/partclone_btrfs-ulist.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -c -o btrfs/partclone_btrfs-ulist.o `test -f 'btrfs/ulist.c' || echo '$(srcdir)/'`btrfs/ulist.c btrfs/partclone_btrfs-ulist.obj: btrfs/ulist.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -MT btrfs/partclone_btrfs-ulist.obj -MD -MP -MF btrfs/$(DEPDIR)/partclone_btrfs-ulist.Tpo -c -o btrfs/partclone_btrfs-ulist.obj `if test -f 'btrfs/ulist.c'; then $(CYGPATH_W) 'btrfs/ulist.c'; else $(CYGPATH_W) '$(srcdir)/btrfs/ulist.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) btrfs/$(DEPDIR)/partclone_btrfs-ulist.Tpo btrfs/$(DEPDIR)/partclone_btrfs-ulist.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btrfs/ulist.c' object='btrfs/partclone_btrfs-ulist.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -c -o btrfs/partclone_btrfs-ulist.obj `if test -f 'btrfs/ulist.c'; then $(CYGPATH_W) 'btrfs/ulist.c'; else $(CYGPATH_W) '$(srcdir)/btrfs/ulist.c'; fi` btrfs/partclone_btrfs-volumes.o: btrfs/volumes.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -MT btrfs/partclone_btrfs-volumes.o -MD -MP -MF btrfs/$(DEPDIR)/partclone_btrfs-volumes.Tpo -c -o btrfs/partclone_btrfs-volumes.o `test -f 'btrfs/volumes.c' || echo '$(srcdir)/'`btrfs/volumes.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) btrfs/$(DEPDIR)/partclone_btrfs-volumes.Tpo btrfs/$(DEPDIR)/partclone_btrfs-volumes.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btrfs/volumes.c' object='btrfs/partclone_btrfs-volumes.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -c -o btrfs/partclone_btrfs-volumes.o `test -f 'btrfs/volumes.c' || echo '$(srcdir)/'`btrfs/volumes.c btrfs/partclone_btrfs-volumes.obj: btrfs/volumes.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -MT btrfs/partclone_btrfs-volumes.obj -MD -MP -MF btrfs/$(DEPDIR)/partclone_btrfs-volumes.Tpo -c -o btrfs/partclone_btrfs-volumes.obj `if test -f 'btrfs/volumes.c'; then $(CYGPATH_W) 'btrfs/volumes.c'; else $(CYGPATH_W) '$(srcdir)/btrfs/volumes.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) btrfs/$(DEPDIR)/partclone_btrfs-volumes.Tpo btrfs/$(DEPDIR)/partclone_btrfs-volumes.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btrfs/volumes.c' object='btrfs/partclone_btrfs-volumes.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -c -o btrfs/partclone_btrfs-volumes.obj `if test -f 'btrfs/volumes.c'; then $(CYGPATH_W) 'btrfs/volumes.c'; else $(CYGPATH_W) '$(srcdir)/btrfs/volumes.c'; fi` btrfs/partclone_btrfs-dir-item.o: btrfs/dir-item.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -MT btrfs/partclone_btrfs-dir-item.o -MD -MP -MF btrfs/$(DEPDIR)/partclone_btrfs-dir-item.Tpo -c -o btrfs/partclone_btrfs-dir-item.o `test -f 'btrfs/dir-item.c' || echo '$(srcdir)/'`btrfs/dir-item.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) btrfs/$(DEPDIR)/partclone_btrfs-dir-item.Tpo btrfs/$(DEPDIR)/partclone_btrfs-dir-item.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btrfs/dir-item.c' object='btrfs/partclone_btrfs-dir-item.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -c -o btrfs/partclone_btrfs-dir-item.o `test -f 'btrfs/dir-item.c' || echo '$(srcdir)/'`btrfs/dir-item.c btrfs/partclone_btrfs-dir-item.obj: btrfs/dir-item.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -MT btrfs/partclone_btrfs-dir-item.obj -MD -MP -MF btrfs/$(DEPDIR)/partclone_btrfs-dir-item.Tpo -c -o btrfs/partclone_btrfs-dir-item.obj `if test -f 'btrfs/dir-item.c'; then $(CYGPATH_W) 'btrfs/dir-item.c'; else $(CYGPATH_W) '$(srcdir)/btrfs/dir-item.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) btrfs/$(DEPDIR)/partclone_btrfs-dir-item.Tpo btrfs/$(DEPDIR)/partclone_btrfs-dir-item.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btrfs/dir-item.c' object='btrfs/partclone_btrfs-dir-item.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -c -o btrfs/partclone_btrfs-dir-item.obj `if test -f 'btrfs/dir-item.c'; then $(CYGPATH_W) 'btrfs/dir-item.c'; else $(CYGPATH_W) '$(srcdir)/btrfs/dir-item.c'; fi` btrfs/partclone_btrfs-inode-map.o: btrfs/inode-map.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -MT btrfs/partclone_btrfs-inode-map.o -MD -MP -MF btrfs/$(DEPDIR)/partclone_btrfs-inode-map.Tpo -c -o btrfs/partclone_btrfs-inode-map.o `test -f 'btrfs/inode-map.c' || echo '$(srcdir)/'`btrfs/inode-map.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) btrfs/$(DEPDIR)/partclone_btrfs-inode-map.Tpo btrfs/$(DEPDIR)/partclone_btrfs-inode-map.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btrfs/inode-map.c' object='btrfs/partclone_btrfs-inode-map.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -c -o btrfs/partclone_btrfs-inode-map.o `test -f 'btrfs/inode-map.c' || echo '$(srcdir)/'`btrfs/inode-map.c btrfs/partclone_btrfs-inode-map.obj: btrfs/inode-map.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -MT btrfs/partclone_btrfs-inode-map.obj -MD -MP -MF btrfs/$(DEPDIR)/partclone_btrfs-inode-map.Tpo -c -o btrfs/partclone_btrfs-inode-map.obj `if test -f 'btrfs/inode-map.c'; then $(CYGPATH_W) 'btrfs/inode-map.c'; else $(CYGPATH_W) '$(srcdir)/btrfs/inode-map.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) btrfs/$(DEPDIR)/partclone_btrfs-inode-map.Tpo btrfs/$(DEPDIR)/partclone_btrfs-inode-map.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btrfs/inode-map.c' object='btrfs/partclone_btrfs-inode-map.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -c -o btrfs/partclone_btrfs-inode-map.obj `if test -f 'btrfs/inode-map.c'; then $(CYGPATH_W) 'btrfs/inode-map.c'; else $(CYGPATH_W) '$(srcdir)/btrfs/inode-map.c'; fi` btrfs/partclone_btrfs-print-tree.o: btrfs/print-tree.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -MT btrfs/partclone_btrfs-print-tree.o -MD -MP -MF btrfs/$(DEPDIR)/partclone_btrfs-print-tree.Tpo -c -o btrfs/partclone_btrfs-print-tree.o `test -f 'btrfs/print-tree.c' || echo '$(srcdir)/'`btrfs/print-tree.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) btrfs/$(DEPDIR)/partclone_btrfs-print-tree.Tpo btrfs/$(DEPDIR)/partclone_btrfs-print-tree.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btrfs/print-tree.c' object='btrfs/partclone_btrfs-print-tree.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -c -o btrfs/partclone_btrfs-print-tree.o `test -f 'btrfs/print-tree.c' || echo '$(srcdir)/'`btrfs/print-tree.c btrfs/partclone_btrfs-print-tree.obj: btrfs/print-tree.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -MT btrfs/partclone_btrfs-print-tree.obj -MD -MP -MF btrfs/$(DEPDIR)/partclone_btrfs-print-tree.Tpo -c -o btrfs/partclone_btrfs-print-tree.obj `if test -f 'btrfs/print-tree.c'; then $(CYGPATH_W) 'btrfs/print-tree.c'; else $(CYGPATH_W) '$(srcdir)/btrfs/print-tree.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) btrfs/$(DEPDIR)/partclone_btrfs-print-tree.Tpo btrfs/$(DEPDIR)/partclone_btrfs-print-tree.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btrfs/print-tree.c' object='btrfs/partclone_btrfs-print-tree.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -c -o btrfs/partclone_btrfs-print-tree.obj `if test -f 'btrfs/print-tree.c'; then $(CYGPATH_W) 'btrfs/print-tree.c'; else $(CYGPATH_W) '$(srcdir)/btrfs/print-tree.c'; fi` btrfs/partclone_btrfs-btrfs-list.o: btrfs/btrfs-list.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -MT btrfs/partclone_btrfs-btrfs-list.o -MD -MP -MF btrfs/$(DEPDIR)/partclone_btrfs-btrfs-list.Tpo -c -o btrfs/partclone_btrfs-btrfs-list.o `test -f 'btrfs/btrfs-list.c' || echo '$(srcdir)/'`btrfs/btrfs-list.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) btrfs/$(DEPDIR)/partclone_btrfs-btrfs-list.Tpo btrfs/$(DEPDIR)/partclone_btrfs-btrfs-list.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btrfs/btrfs-list.c' object='btrfs/partclone_btrfs-btrfs-list.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -c -o btrfs/partclone_btrfs-btrfs-list.o `test -f 'btrfs/btrfs-list.c' || echo '$(srcdir)/'`btrfs/btrfs-list.c btrfs/partclone_btrfs-btrfs-list.obj: btrfs/btrfs-list.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -MT btrfs/partclone_btrfs-btrfs-list.obj -MD -MP -MF btrfs/$(DEPDIR)/partclone_btrfs-btrfs-list.Tpo -c -o btrfs/partclone_btrfs-btrfs-list.obj `if test -f 'btrfs/btrfs-list.c'; then $(CYGPATH_W) 'btrfs/btrfs-list.c'; else $(CYGPATH_W) '$(srcdir)/btrfs/btrfs-list.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) btrfs/$(DEPDIR)/partclone_btrfs-btrfs-list.Tpo btrfs/$(DEPDIR)/partclone_btrfs-btrfs-list.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btrfs/btrfs-list.c' object='btrfs/partclone_btrfs-btrfs-list.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -c -o btrfs/partclone_btrfs-btrfs-list.obj `if test -f 'btrfs/btrfs-list.c'; then $(CYGPATH_W) 'btrfs/btrfs-list.c'; else $(CYGPATH_W) '$(srcdir)/btrfs/btrfs-list.c'; fi` btrfs/partclone_btrfs-disk-io.o: btrfs/disk-io.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -MT btrfs/partclone_btrfs-disk-io.o -MD -MP -MF btrfs/$(DEPDIR)/partclone_btrfs-disk-io.Tpo -c -o btrfs/partclone_btrfs-disk-io.o `test -f 'btrfs/disk-io.c' || echo '$(srcdir)/'`btrfs/disk-io.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) btrfs/$(DEPDIR)/partclone_btrfs-disk-io.Tpo btrfs/$(DEPDIR)/partclone_btrfs-disk-io.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btrfs/disk-io.c' object='btrfs/partclone_btrfs-disk-io.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -c -o btrfs/partclone_btrfs-disk-io.o `test -f 'btrfs/disk-io.c' || echo '$(srcdir)/'`btrfs/disk-io.c btrfs/partclone_btrfs-disk-io.obj: btrfs/disk-io.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -MT btrfs/partclone_btrfs-disk-io.obj -MD -MP -MF btrfs/$(DEPDIR)/partclone_btrfs-disk-io.Tpo -c -o btrfs/partclone_btrfs-disk-io.obj `if test -f 'btrfs/disk-io.c'; then $(CYGPATH_W) 'btrfs/disk-io.c'; else $(CYGPATH_W) '$(srcdir)/btrfs/disk-io.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) btrfs/$(DEPDIR)/partclone_btrfs-disk-io.Tpo btrfs/$(DEPDIR)/partclone_btrfs-disk-io.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btrfs/disk-io.c' object='btrfs/partclone_btrfs-disk-io.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -c -o btrfs/partclone_btrfs-disk-io.obj `if test -f 'btrfs/disk-io.c'; then $(CYGPATH_W) 'btrfs/disk-io.c'; else $(CYGPATH_W) '$(srcdir)/btrfs/disk-io.c'; fi` btrfs/partclone_btrfs-extent-tree.o: btrfs/extent-tree.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -MT btrfs/partclone_btrfs-extent-tree.o -MD -MP -MF btrfs/$(DEPDIR)/partclone_btrfs-extent-tree.Tpo -c -o btrfs/partclone_btrfs-extent-tree.o `test -f 'btrfs/extent-tree.c' || echo '$(srcdir)/'`btrfs/extent-tree.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) btrfs/$(DEPDIR)/partclone_btrfs-extent-tree.Tpo btrfs/$(DEPDIR)/partclone_btrfs-extent-tree.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btrfs/extent-tree.c' object='btrfs/partclone_btrfs-extent-tree.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -c -o btrfs/partclone_btrfs-extent-tree.o `test -f 'btrfs/extent-tree.c' || echo '$(srcdir)/'`btrfs/extent-tree.c btrfs/partclone_btrfs-extent-tree.obj: btrfs/extent-tree.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -MT btrfs/partclone_btrfs-extent-tree.obj -MD -MP -MF btrfs/$(DEPDIR)/partclone_btrfs-extent-tree.Tpo -c -o btrfs/partclone_btrfs-extent-tree.obj `if test -f 'btrfs/extent-tree.c'; then $(CYGPATH_W) 'btrfs/extent-tree.c'; else $(CYGPATH_W) '$(srcdir)/btrfs/extent-tree.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) btrfs/$(DEPDIR)/partclone_btrfs-extent-tree.Tpo btrfs/$(DEPDIR)/partclone_btrfs-extent-tree.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btrfs/extent-tree.c' object='btrfs/partclone_btrfs-extent-tree.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -c -o btrfs/partclone_btrfs-extent-tree.obj `if test -f 'btrfs/extent-tree.c'; then $(CYGPATH_W) 'btrfs/extent-tree.c'; else $(CYGPATH_W) '$(srcdir)/btrfs/extent-tree.c'; fi` btrfs/partclone_btrfs-raid6.o: btrfs/raid6.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -MT btrfs/partclone_btrfs-raid6.o -MD -MP -MF btrfs/$(DEPDIR)/partclone_btrfs-raid6.Tpo -c -o btrfs/partclone_btrfs-raid6.o `test -f 'btrfs/raid6.c' || echo '$(srcdir)/'`btrfs/raid6.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) btrfs/$(DEPDIR)/partclone_btrfs-raid6.Tpo btrfs/$(DEPDIR)/partclone_btrfs-raid6.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btrfs/raid6.c' object='btrfs/partclone_btrfs-raid6.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -c -o btrfs/partclone_btrfs-raid6.o `test -f 'btrfs/raid6.c' || echo '$(srcdir)/'`btrfs/raid6.c btrfs/partclone_btrfs-raid6.obj: btrfs/raid6.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -MT btrfs/partclone_btrfs-raid6.obj -MD -MP -MF btrfs/$(DEPDIR)/partclone_btrfs-raid6.Tpo -c -o btrfs/partclone_btrfs-raid6.obj `if test -f 'btrfs/raid6.c'; then $(CYGPATH_W) 'btrfs/raid6.c'; else $(CYGPATH_W) '$(srcdir)/btrfs/raid6.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) btrfs/$(DEPDIR)/partclone_btrfs-raid6.Tpo btrfs/$(DEPDIR)/partclone_btrfs-raid6.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btrfs/raid6.c' object='btrfs/partclone_btrfs-raid6.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -c -o btrfs/partclone_btrfs-raid6.obj `if test -f 'btrfs/raid6.c'; then $(CYGPATH_W) 'btrfs/raid6.c'; else $(CYGPATH_W) '$(srcdir)/btrfs/raid6.c'; fi` btrfs/partclone_btrfs-send-stream.o: btrfs/send-stream.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -MT btrfs/partclone_btrfs-send-stream.o -MD -MP -MF btrfs/$(DEPDIR)/partclone_btrfs-send-stream.Tpo -c -o btrfs/partclone_btrfs-send-stream.o `test -f 'btrfs/send-stream.c' || echo '$(srcdir)/'`btrfs/send-stream.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) btrfs/$(DEPDIR)/partclone_btrfs-send-stream.Tpo btrfs/$(DEPDIR)/partclone_btrfs-send-stream.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btrfs/send-stream.c' object='btrfs/partclone_btrfs-send-stream.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -c -o btrfs/partclone_btrfs-send-stream.o `test -f 'btrfs/send-stream.c' || echo '$(srcdir)/'`btrfs/send-stream.c btrfs/partclone_btrfs-send-stream.obj: btrfs/send-stream.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -MT btrfs/partclone_btrfs-send-stream.obj -MD -MP -MF btrfs/$(DEPDIR)/partclone_btrfs-send-stream.Tpo -c -o btrfs/partclone_btrfs-send-stream.obj `if test -f 'btrfs/send-stream.c'; then $(CYGPATH_W) 'btrfs/send-stream.c'; else $(CYGPATH_W) '$(srcdir)/btrfs/send-stream.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) btrfs/$(DEPDIR)/partclone_btrfs-send-stream.Tpo btrfs/$(DEPDIR)/partclone_btrfs-send-stream.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btrfs/send-stream.c' object='btrfs/partclone_btrfs-send-stream.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -c -o btrfs/partclone_btrfs-send-stream.obj `if test -f 'btrfs/send-stream.c'; then $(CYGPATH_W) 'btrfs/send-stream.c'; else $(CYGPATH_W) '$(srcdir)/btrfs/send-stream.c'; fi` btrfs/partclone_btrfs-utils.o: btrfs/utils.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -MT btrfs/partclone_btrfs-utils.o -MD -MP -MF btrfs/$(DEPDIR)/partclone_btrfs-utils.Tpo -c -o btrfs/partclone_btrfs-utils.o `test -f 'btrfs/utils.c' || echo '$(srcdir)/'`btrfs/utils.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) btrfs/$(DEPDIR)/partclone_btrfs-utils.Tpo btrfs/$(DEPDIR)/partclone_btrfs-utils.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btrfs/utils.c' object='btrfs/partclone_btrfs-utils.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -c -o btrfs/partclone_btrfs-utils.o `test -f 'btrfs/utils.c' || echo '$(srcdir)/'`btrfs/utils.c btrfs/partclone_btrfs-utils.obj: btrfs/utils.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -MT btrfs/partclone_btrfs-utils.obj -MD -MP -MF btrfs/$(DEPDIR)/partclone_btrfs-utils.Tpo -c -o btrfs/partclone_btrfs-utils.obj `if test -f 'btrfs/utils.c'; then $(CYGPATH_W) 'btrfs/utils.c'; else $(CYGPATH_W) '$(srcdir)/btrfs/utils.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) btrfs/$(DEPDIR)/partclone_btrfs-utils.Tpo btrfs/$(DEPDIR)/partclone_btrfs-utils.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btrfs/utils.c' object='btrfs/partclone_btrfs-utils.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -c -o btrfs/partclone_btrfs-utils.obj `if test -f 'btrfs/utils.c'; then $(CYGPATH_W) 'btrfs/utils.c'; else $(CYGPATH_W) '$(srcdir)/btrfs/utils.c'; fi` btrfs/partclone_btrfs-file-item.o: btrfs/file-item.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -MT btrfs/partclone_btrfs-file-item.o -MD -MP -MF btrfs/$(DEPDIR)/partclone_btrfs-file-item.Tpo -c -o btrfs/partclone_btrfs-file-item.o `test -f 'btrfs/file-item.c' || echo '$(srcdir)/'`btrfs/file-item.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) btrfs/$(DEPDIR)/partclone_btrfs-file-item.Tpo btrfs/$(DEPDIR)/partclone_btrfs-file-item.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btrfs/file-item.c' object='btrfs/partclone_btrfs-file-item.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -c -o btrfs/partclone_btrfs-file-item.o `test -f 'btrfs/file-item.c' || echo '$(srcdir)/'`btrfs/file-item.c btrfs/partclone_btrfs-file-item.obj: btrfs/file-item.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -MT btrfs/partclone_btrfs-file-item.obj -MD -MP -MF btrfs/$(DEPDIR)/partclone_btrfs-file-item.Tpo -c -o btrfs/partclone_btrfs-file-item.obj `if test -f 'btrfs/file-item.c'; then $(CYGPATH_W) 'btrfs/file-item.c'; else $(CYGPATH_W) '$(srcdir)/btrfs/file-item.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) btrfs/$(DEPDIR)/partclone_btrfs-file-item.Tpo btrfs/$(DEPDIR)/partclone_btrfs-file-item.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btrfs/file-item.c' object='btrfs/partclone_btrfs-file-item.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -c -o btrfs/partclone_btrfs-file-item.obj `if test -f 'btrfs/file-item.c'; then $(CYGPATH_W) 'btrfs/file-item.c'; else $(CYGPATH_W) '$(srcdir)/btrfs/file-item.c'; fi` btrfs/partclone_btrfs-qgroup.o: btrfs/qgroup.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -MT btrfs/partclone_btrfs-qgroup.o -MD -MP -MF btrfs/$(DEPDIR)/partclone_btrfs-qgroup.Tpo -c -o btrfs/partclone_btrfs-qgroup.o `test -f 'btrfs/qgroup.c' || echo '$(srcdir)/'`btrfs/qgroup.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) btrfs/$(DEPDIR)/partclone_btrfs-qgroup.Tpo btrfs/$(DEPDIR)/partclone_btrfs-qgroup.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btrfs/qgroup.c' object='btrfs/partclone_btrfs-qgroup.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -c -o btrfs/partclone_btrfs-qgroup.o `test -f 'btrfs/qgroup.c' || echo '$(srcdir)/'`btrfs/qgroup.c btrfs/partclone_btrfs-qgroup.obj: btrfs/qgroup.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -MT btrfs/partclone_btrfs-qgroup.obj -MD -MP -MF btrfs/$(DEPDIR)/partclone_btrfs-qgroup.Tpo -c -o btrfs/partclone_btrfs-qgroup.obj `if test -f 'btrfs/qgroup.c'; then $(CYGPATH_W) 'btrfs/qgroup.c'; else $(CYGPATH_W) '$(srcdir)/btrfs/qgroup.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) btrfs/$(DEPDIR)/partclone_btrfs-qgroup.Tpo btrfs/$(DEPDIR)/partclone_btrfs-qgroup.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btrfs/qgroup.c' object='btrfs/partclone_btrfs-qgroup.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -c -o btrfs/partclone_btrfs-qgroup.obj `if test -f 'btrfs/qgroup.c'; then $(CYGPATH_W) 'btrfs/qgroup.c'; else $(CYGPATH_W) '$(srcdir)/btrfs/qgroup.c'; fi` btrfs/partclone_btrfs-rbtree.o: btrfs/rbtree.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -MT btrfs/partclone_btrfs-rbtree.o -MD -MP -MF btrfs/$(DEPDIR)/partclone_btrfs-rbtree.Tpo -c -o btrfs/partclone_btrfs-rbtree.o `test -f 'btrfs/rbtree.c' || echo '$(srcdir)/'`btrfs/rbtree.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) btrfs/$(DEPDIR)/partclone_btrfs-rbtree.Tpo btrfs/$(DEPDIR)/partclone_btrfs-rbtree.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btrfs/rbtree.c' object='btrfs/partclone_btrfs-rbtree.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -c -o btrfs/partclone_btrfs-rbtree.o `test -f 'btrfs/rbtree.c' || echo '$(srcdir)/'`btrfs/rbtree.c btrfs/partclone_btrfs-rbtree.obj: btrfs/rbtree.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -MT btrfs/partclone_btrfs-rbtree.obj -MD -MP -MF btrfs/$(DEPDIR)/partclone_btrfs-rbtree.Tpo -c -o btrfs/partclone_btrfs-rbtree.obj `if test -f 'btrfs/rbtree.c'; then $(CYGPATH_W) 'btrfs/rbtree.c'; else $(CYGPATH_W) '$(srcdir)/btrfs/rbtree.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) btrfs/$(DEPDIR)/partclone_btrfs-rbtree.Tpo btrfs/$(DEPDIR)/partclone_btrfs-rbtree.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btrfs/rbtree.c' object='btrfs/partclone_btrfs-rbtree.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -c -o btrfs/partclone_btrfs-rbtree.obj `if test -f 'btrfs/rbtree.c'; then $(CYGPATH_W) 'btrfs/rbtree.c'; else $(CYGPATH_W) '$(srcdir)/btrfs/rbtree.c'; fi` btrfs/partclone_btrfs-crc32c.o: btrfs/crc32c.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -MT btrfs/partclone_btrfs-crc32c.o -MD -MP -MF btrfs/$(DEPDIR)/partclone_btrfs-crc32c.Tpo -c -o btrfs/partclone_btrfs-crc32c.o `test -f 'btrfs/crc32c.c' || echo '$(srcdir)/'`btrfs/crc32c.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) btrfs/$(DEPDIR)/partclone_btrfs-crc32c.Tpo btrfs/$(DEPDIR)/partclone_btrfs-crc32c.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btrfs/crc32c.c' object='btrfs/partclone_btrfs-crc32c.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -c -o btrfs/partclone_btrfs-crc32c.o `test -f 'btrfs/crc32c.c' || echo '$(srcdir)/'`btrfs/crc32c.c btrfs/partclone_btrfs-crc32c.obj: btrfs/crc32c.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -MT btrfs/partclone_btrfs-crc32c.obj -MD -MP -MF btrfs/$(DEPDIR)/partclone_btrfs-crc32c.Tpo -c -o btrfs/partclone_btrfs-crc32c.obj `if test -f 'btrfs/crc32c.c'; then $(CYGPATH_W) 'btrfs/crc32c.c'; else $(CYGPATH_W) '$(srcdir)/btrfs/crc32c.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) btrfs/$(DEPDIR)/partclone_btrfs-crc32c.Tpo btrfs/$(DEPDIR)/partclone_btrfs-crc32c.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btrfs/crc32c.c' object='btrfs/partclone_btrfs-crc32c.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -c -o btrfs/partclone_btrfs-crc32c.obj `if test -f 'btrfs/crc32c.c'; then $(CYGPATH_W) 'btrfs/crc32c.c'; else $(CYGPATH_W) '$(srcdir)/btrfs/crc32c.c'; fi` btrfs/partclone_btrfs-free-space-cache.o: btrfs/free-space-cache.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -MT btrfs/partclone_btrfs-free-space-cache.o -MD -MP -MF btrfs/$(DEPDIR)/partclone_btrfs-free-space-cache.Tpo -c -o btrfs/partclone_btrfs-free-space-cache.o `test -f 'btrfs/free-space-cache.c' || echo '$(srcdir)/'`btrfs/free-space-cache.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) btrfs/$(DEPDIR)/partclone_btrfs-free-space-cache.Tpo btrfs/$(DEPDIR)/partclone_btrfs-free-space-cache.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btrfs/free-space-cache.c' object='btrfs/partclone_btrfs-free-space-cache.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -c -o btrfs/partclone_btrfs-free-space-cache.o `test -f 'btrfs/free-space-cache.c' || echo '$(srcdir)/'`btrfs/free-space-cache.c btrfs/partclone_btrfs-free-space-cache.obj: btrfs/free-space-cache.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -MT btrfs/partclone_btrfs-free-space-cache.obj -MD -MP -MF btrfs/$(DEPDIR)/partclone_btrfs-free-space-cache.Tpo -c -o btrfs/partclone_btrfs-free-space-cache.obj `if test -f 'btrfs/free-space-cache.c'; then $(CYGPATH_W) 'btrfs/free-space-cache.c'; else $(CYGPATH_W) '$(srcdir)/btrfs/free-space-cache.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) btrfs/$(DEPDIR)/partclone_btrfs-free-space-cache.Tpo btrfs/$(DEPDIR)/partclone_btrfs-free-space-cache.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btrfs/free-space-cache.c' object='btrfs/partclone_btrfs-free-space-cache.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -c -o btrfs/partclone_btrfs-free-space-cache.obj `if test -f 'btrfs/free-space-cache.c'; then $(CYGPATH_W) 'btrfs/free-space-cache.c'; else $(CYGPATH_W) '$(srcdir)/btrfs/free-space-cache.c'; fi` btrfs/partclone_btrfs-send-utils.o: btrfs/send-utils.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -MT btrfs/partclone_btrfs-send-utils.o -MD -MP -MF btrfs/$(DEPDIR)/partclone_btrfs-send-utils.Tpo -c -o btrfs/partclone_btrfs-send-utils.o `test -f 'btrfs/send-utils.c' || echo '$(srcdir)/'`btrfs/send-utils.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) btrfs/$(DEPDIR)/partclone_btrfs-send-utils.Tpo btrfs/$(DEPDIR)/partclone_btrfs-send-utils.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btrfs/send-utils.c' object='btrfs/partclone_btrfs-send-utils.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -c -o btrfs/partclone_btrfs-send-utils.o `test -f 'btrfs/send-utils.c' || echo '$(srcdir)/'`btrfs/send-utils.c btrfs/partclone_btrfs-send-utils.obj: btrfs/send-utils.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -MT btrfs/partclone_btrfs-send-utils.obj -MD -MP -MF btrfs/$(DEPDIR)/partclone_btrfs-send-utils.Tpo -c -o btrfs/partclone_btrfs-send-utils.obj `if test -f 'btrfs/send-utils.c'; then $(CYGPATH_W) 'btrfs/send-utils.c'; else $(CYGPATH_W) '$(srcdir)/btrfs/send-utils.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) btrfs/$(DEPDIR)/partclone_btrfs-send-utils.Tpo btrfs/$(DEPDIR)/partclone_btrfs-send-utils.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btrfs/send-utils.c' object='btrfs/partclone_btrfs-send-utils.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -c -o btrfs/partclone_btrfs-send-utils.obj `if test -f 'btrfs/send-utils.c'; then $(CYGPATH_W) 'btrfs/send-utils.c'; else $(CYGPATH_W) '$(srcdir)/btrfs/send-utils.c'; fi` btrfs/partclone_btrfs-utils-lib.o: btrfs/utils-lib.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -MT btrfs/partclone_btrfs-utils-lib.o -MD -MP -MF btrfs/$(DEPDIR)/partclone_btrfs-utils-lib.Tpo -c -o btrfs/partclone_btrfs-utils-lib.o `test -f 'btrfs/utils-lib.c' || echo '$(srcdir)/'`btrfs/utils-lib.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) btrfs/$(DEPDIR)/partclone_btrfs-utils-lib.Tpo btrfs/$(DEPDIR)/partclone_btrfs-utils-lib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btrfs/utils-lib.c' object='btrfs/partclone_btrfs-utils-lib.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -c -o btrfs/partclone_btrfs-utils-lib.o `test -f 'btrfs/utils-lib.c' || echo '$(srcdir)/'`btrfs/utils-lib.c btrfs/partclone_btrfs-utils-lib.obj: btrfs/utils-lib.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -MT btrfs/partclone_btrfs-utils-lib.obj -MD -MP -MF btrfs/$(DEPDIR)/partclone_btrfs-utils-lib.Tpo -c -o btrfs/partclone_btrfs-utils-lib.obj `if test -f 'btrfs/utils-lib.c'; then $(CYGPATH_W) 'btrfs/utils-lib.c'; else $(CYGPATH_W) '$(srcdir)/btrfs/utils-lib.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) btrfs/$(DEPDIR)/partclone_btrfs-utils-lib.Tpo btrfs/$(DEPDIR)/partclone_btrfs-utils-lib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btrfs/utils-lib.c' object='btrfs/partclone_btrfs-utils-lib.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -c -o btrfs/partclone_btrfs-utils-lib.obj `if test -f 'btrfs/utils-lib.c'; then $(CYGPATH_W) 'btrfs/utils-lib.c'; else $(CYGPATH_W) '$(srcdir)/btrfs/utils-lib.c'; fi` btrfs/partclone_btrfs-rbtree-utils.o: btrfs/rbtree-utils.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -MT btrfs/partclone_btrfs-rbtree-utils.o -MD -MP -MF btrfs/$(DEPDIR)/partclone_btrfs-rbtree-utils.Tpo -c -o btrfs/partclone_btrfs-rbtree-utils.o `test -f 'btrfs/rbtree-utils.c' || echo '$(srcdir)/'`btrfs/rbtree-utils.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) btrfs/$(DEPDIR)/partclone_btrfs-rbtree-utils.Tpo btrfs/$(DEPDIR)/partclone_btrfs-rbtree-utils.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btrfs/rbtree-utils.c' object='btrfs/partclone_btrfs-rbtree-utils.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -c -o btrfs/partclone_btrfs-rbtree-utils.o `test -f 'btrfs/rbtree-utils.c' || echo '$(srcdir)/'`btrfs/rbtree-utils.c btrfs/partclone_btrfs-rbtree-utils.obj: btrfs/rbtree-utils.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -MT btrfs/partclone_btrfs-rbtree-utils.obj -MD -MP -MF btrfs/$(DEPDIR)/partclone_btrfs-rbtree-utils.Tpo -c -o btrfs/partclone_btrfs-rbtree-utils.obj `if test -f 'btrfs/rbtree-utils.c'; then $(CYGPATH_W) 'btrfs/rbtree-utils.c'; else $(CYGPATH_W) '$(srcdir)/btrfs/rbtree-utils.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) btrfs/$(DEPDIR)/partclone_btrfs-rbtree-utils.Tpo btrfs/$(DEPDIR)/partclone_btrfs-rbtree-utils.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btrfs/rbtree-utils.c' object='btrfs/partclone_btrfs-rbtree-utils.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -c -o btrfs/partclone_btrfs-rbtree-utils.obj `if test -f 'btrfs/rbtree-utils.c'; then $(CYGPATH_W) 'btrfs/rbtree-utils.c'; else $(CYGPATH_W) '$(srcdir)/btrfs/rbtree-utils.c'; fi` btrfs/partclone_btrfs-extent-cache.o: btrfs/extent-cache.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -MT btrfs/partclone_btrfs-extent-cache.o -MD -MP -MF btrfs/$(DEPDIR)/partclone_btrfs-extent-cache.Tpo -c -o btrfs/partclone_btrfs-extent-cache.o `test -f 'btrfs/extent-cache.c' || echo '$(srcdir)/'`btrfs/extent-cache.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) btrfs/$(DEPDIR)/partclone_btrfs-extent-cache.Tpo btrfs/$(DEPDIR)/partclone_btrfs-extent-cache.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btrfs/extent-cache.c' object='btrfs/partclone_btrfs-extent-cache.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -c -o btrfs/partclone_btrfs-extent-cache.o `test -f 'btrfs/extent-cache.c' || echo '$(srcdir)/'`btrfs/extent-cache.c btrfs/partclone_btrfs-extent-cache.obj: btrfs/extent-cache.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -MT btrfs/partclone_btrfs-extent-cache.obj -MD -MP -MF btrfs/$(DEPDIR)/partclone_btrfs-extent-cache.Tpo -c -o btrfs/partclone_btrfs-extent-cache.obj `if test -f 'btrfs/extent-cache.c'; then $(CYGPATH_W) 'btrfs/extent-cache.c'; else $(CYGPATH_W) '$(srcdir)/btrfs/extent-cache.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) btrfs/$(DEPDIR)/partclone_btrfs-extent-cache.Tpo btrfs/$(DEPDIR)/partclone_btrfs-extent-cache.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btrfs/extent-cache.c' object='btrfs/partclone_btrfs-extent-cache.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -c -o btrfs/partclone_btrfs-extent-cache.obj `if test -f 'btrfs/extent-cache.c'; then $(CYGPATH_W) 'btrfs/extent-cache.c'; else $(CYGPATH_W) '$(srcdir)/btrfs/extent-cache.c'; fi` btrfs/partclone_btrfs-list_sort.o: btrfs/list_sort.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -MT btrfs/partclone_btrfs-list_sort.o -MD -MP -MF btrfs/$(DEPDIR)/partclone_btrfs-list_sort.Tpo -c -o btrfs/partclone_btrfs-list_sort.o `test -f 'btrfs/list_sort.c' || echo '$(srcdir)/'`btrfs/list_sort.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) btrfs/$(DEPDIR)/partclone_btrfs-list_sort.Tpo btrfs/$(DEPDIR)/partclone_btrfs-list_sort.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btrfs/list_sort.c' object='btrfs/partclone_btrfs-list_sort.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -c -o btrfs/partclone_btrfs-list_sort.o `test -f 'btrfs/list_sort.c' || echo '$(srcdir)/'`btrfs/list_sort.c btrfs/partclone_btrfs-list_sort.obj: btrfs/list_sort.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -MT btrfs/partclone_btrfs-list_sort.obj -MD -MP -MF btrfs/$(DEPDIR)/partclone_btrfs-list_sort.Tpo -c -o btrfs/partclone_btrfs-list_sort.obj `if test -f 'btrfs/list_sort.c'; then $(CYGPATH_W) 'btrfs/list_sort.c'; else $(CYGPATH_W) '$(srcdir)/btrfs/list_sort.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) btrfs/$(DEPDIR)/partclone_btrfs-list_sort.Tpo btrfs/$(DEPDIR)/partclone_btrfs-list_sort.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btrfs/list_sort.c' object='btrfs/partclone_btrfs-list_sort.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -c -o btrfs/partclone_btrfs-list_sort.obj `if test -f 'btrfs/list_sort.c'; then $(CYGPATH_W) 'btrfs/list_sort.c'; else $(CYGPATH_W) '$(srcdir)/btrfs/list_sort.c'; fi` btrfs/partclone_btrfs-qgroup-verify.o: btrfs/qgroup-verify.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -MT btrfs/partclone_btrfs-qgroup-verify.o -MD -MP -MF btrfs/$(DEPDIR)/partclone_btrfs-qgroup-verify.Tpo -c -o btrfs/partclone_btrfs-qgroup-verify.o `test -f 'btrfs/qgroup-verify.c' || echo '$(srcdir)/'`btrfs/qgroup-verify.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) btrfs/$(DEPDIR)/partclone_btrfs-qgroup-verify.Tpo btrfs/$(DEPDIR)/partclone_btrfs-qgroup-verify.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btrfs/qgroup-verify.c' object='btrfs/partclone_btrfs-qgroup-verify.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -c -o btrfs/partclone_btrfs-qgroup-verify.o `test -f 'btrfs/qgroup-verify.c' || echo '$(srcdir)/'`btrfs/qgroup-verify.c btrfs/partclone_btrfs-qgroup-verify.obj: btrfs/qgroup-verify.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -MT btrfs/partclone_btrfs-qgroup-verify.obj -MD -MP -MF btrfs/$(DEPDIR)/partclone_btrfs-qgroup-verify.Tpo -c -o btrfs/partclone_btrfs-qgroup-verify.obj `if test -f 'btrfs/qgroup-verify.c'; then $(CYGPATH_W) 'btrfs/qgroup-verify.c'; else $(CYGPATH_W) '$(srcdir)/btrfs/qgroup-verify.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) btrfs/$(DEPDIR)/partclone_btrfs-qgroup-verify.Tpo btrfs/$(DEPDIR)/partclone_btrfs-qgroup-verify.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btrfs/qgroup-verify.c' object='btrfs/partclone_btrfs-qgroup-verify.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -c -o btrfs/partclone_btrfs-qgroup-verify.obj `if test -f 'btrfs/qgroup-verify.c'; then $(CYGPATH_W) 'btrfs/qgroup-verify.c'; else $(CYGPATH_W) '$(srcdir)/btrfs/qgroup-verify.c'; fi` btrfs/partclone_btrfs-repair.o: btrfs/repair.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -MT btrfs/partclone_btrfs-repair.o -MD -MP -MF btrfs/$(DEPDIR)/partclone_btrfs-repair.Tpo -c -o btrfs/partclone_btrfs-repair.o `test -f 'btrfs/repair.c' || echo '$(srcdir)/'`btrfs/repair.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) btrfs/$(DEPDIR)/partclone_btrfs-repair.Tpo btrfs/$(DEPDIR)/partclone_btrfs-repair.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btrfs/repair.c' object='btrfs/partclone_btrfs-repair.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -c -o btrfs/partclone_btrfs-repair.o `test -f 'btrfs/repair.c' || echo '$(srcdir)/'`btrfs/repair.c btrfs/partclone_btrfs-repair.obj: btrfs/repair.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -MT btrfs/partclone_btrfs-repair.obj -MD -MP -MF btrfs/$(DEPDIR)/partclone_btrfs-repair.Tpo -c -o btrfs/partclone_btrfs-repair.obj `if test -f 'btrfs/repair.c'; then $(CYGPATH_W) 'btrfs/repair.c'; else $(CYGPATH_W) '$(srcdir)/btrfs/repair.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) btrfs/$(DEPDIR)/partclone_btrfs-repair.Tpo btrfs/$(DEPDIR)/partclone_btrfs-repair.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btrfs/repair.c' object='btrfs/partclone_btrfs-repair.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -c -o btrfs/partclone_btrfs-repair.obj `if test -f 'btrfs/repair.c'; then $(CYGPATH_W) 'btrfs/repair.c'; else $(CYGPATH_W) '$(srcdir)/btrfs/repair.c'; fi` btrfs/partclone_btrfs-uuid-tree.o: btrfs/uuid-tree.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -MT btrfs/partclone_btrfs-uuid-tree.o -MD -MP -MF btrfs/$(DEPDIR)/partclone_btrfs-uuid-tree.Tpo -c -o btrfs/partclone_btrfs-uuid-tree.o `test -f 'btrfs/uuid-tree.c' || echo '$(srcdir)/'`btrfs/uuid-tree.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) btrfs/$(DEPDIR)/partclone_btrfs-uuid-tree.Tpo btrfs/$(DEPDIR)/partclone_btrfs-uuid-tree.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btrfs/uuid-tree.c' object='btrfs/partclone_btrfs-uuid-tree.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -c -o btrfs/partclone_btrfs-uuid-tree.o `test -f 'btrfs/uuid-tree.c' || echo '$(srcdir)/'`btrfs/uuid-tree.c btrfs/partclone_btrfs-uuid-tree.obj: btrfs/uuid-tree.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -MT btrfs/partclone_btrfs-uuid-tree.obj -MD -MP -MF btrfs/$(DEPDIR)/partclone_btrfs-uuid-tree.Tpo -c -o btrfs/partclone_btrfs-uuid-tree.obj `if test -f 'btrfs/uuid-tree.c'; then $(CYGPATH_W) 'btrfs/uuid-tree.c'; else $(CYGPATH_W) '$(srcdir)/btrfs/uuid-tree.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) btrfs/$(DEPDIR)/partclone_btrfs-uuid-tree.Tpo btrfs/$(DEPDIR)/partclone_btrfs-uuid-tree.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btrfs/uuid-tree.c' object='btrfs/partclone_btrfs-uuid-tree.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -c -o btrfs/partclone_btrfs-uuid-tree.obj `if test -f 'btrfs/uuid-tree.c'; then $(CYGPATH_W) 'btrfs/uuid-tree.c'; else $(CYGPATH_W) '$(srcdir)/btrfs/uuid-tree.c'; fi` btrfs/partclone_btrfs-ctree.o: btrfs/ctree.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -MT btrfs/partclone_btrfs-ctree.o -MD -MP -MF btrfs/$(DEPDIR)/partclone_btrfs-ctree.Tpo -c -o btrfs/partclone_btrfs-ctree.o `test -f 'btrfs/ctree.c' || echo '$(srcdir)/'`btrfs/ctree.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) btrfs/$(DEPDIR)/partclone_btrfs-ctree.Tpo btrfs/$(DEPDIR)/partclone_btrfs-ctree.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btrfs/ctree.c' object='btrfs/partclone_btrfs-ctree.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -c -o btrfs/partclone_btrfs-ctree.o `test -f 'btrfs/ctree.c' || echo '$(srcdir)/'`btrfs/ctree.c btrfs/partclone_btrfs-ctree.obj: btrfs/ctree.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -MT btrfs/partclone_btrfs-ctree.obj -MD -MP -MF btrfs/$(DEPDIR)/partclone_btrfs-ctree.Tpo -c -o btrfs/partclone_btrfs-ctree.obj `if test -f 'btrfs/ctree.c'; then $(CYGPATH_W) 'btrfs/ctree.c'; else $(CYGPATH_W) '$(srcdir)/btrfs/ctree.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) btrfs/$(DEPDIR)/partclone_btrfs-ctree.Tpo btrfs/$(DEPDIR)/partclone_btrfs-ctree.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btrfs/ctree.c' object='btrfs/partclone_btrfs-ctree.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_btrfs_CFLAGS) $(CFLAGS) -c -o btrfs/partclone_btrfs-ctree.obj `if test -f 'btrfs/ctree.c'; then $(CYGPATH_W) 'btrfs/ctree.c'; else $(CYGPATH_W) '$(srcdir)/btrfs/ctree.c'; fi` partclone_chkimg-main.o: main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_chkimg_CFLAGS) $(CFLAGS) -MT partclone_chkimg-main.o -MD -MP -MF $(DEPDIR)/partclone_chkimg-main.Tpo -c -o partclone_chkimg-main.o `test -f 'main.c' || echo '$(srcdir)/'`main.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_chkimg-main.Tpo $(DEPDIR)/partclone_chkimg-main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='main.c' object='partclone_chkimg-main.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_chkimg_CFLAGS) $(CFLAGS) -c -o partclone_chkimg-main.o `test -f 'main.c' || echo '$(srcdir)/'`main.c partclone_chkimg-main.obj: main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_chkimg_CFLAGS) $(CFLAGS) -MT partclone_chkimg-main.obj -MD -MP -MF $(DEPDIR)/partclone_chkimg-main.Tpo -c -o partclone_chkimg-main.obj `if test -f 'main.c'; then $(CYGPATH_W) 'main.c'; else $(CYGPATH_W) '$(srcdir)/main.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_chkimg-main.Tpo $(DEPDIR)/partclone_chkimg-main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='main.c' object='partclone_chkimg-main.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_chkimg_CFLAGS) $(CFLAGS) -c -o partclone_chkimg-main.obj `if test -f 'main.c'; then $(CYGPATH_W) 'main.c'; else $(CYGPATH_W) '$(srcdir)/main.c'; fi` partclone_chkimg-partclone.o: partclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_chkimg_CFLAGS) $(CFLAGS) -MT partclone_chkimg-partclone.o -MD -MP -MF $(DEPDIR)/partclone_chkimg-partclone.Tpo -c -o partclone_chkimg-partclone.o `test -f 'partclone.c' || echo '$(srcdir)/'`partclone.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_chkimg-partclone.Tpo $(DEPDIR)/partclone_chkimg-partclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='partclone.c' object='partclone_chkimg-partclone.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_chkimg_CFLAGS) $(CFLAGS) -c -o partclone_chkimg-partclone.o `test -f 'partclone.c' || echo '$(srcdir)/'`partclone.c partclone_chkimg-partclone.obj: partclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_chkimg_CFLAGS) $(CFLAGS) -MT partclone_chkimg-partclone.obj -MD -MP -MF $(DEPDIR)/partclone_chkimg-partclone.Tpo -c -o partclone_chkimg-partclone.obj `if test -f 'partclone.c'; then $(CYGPATH_W) 'partclone.c'; else $(CYGPATH_W) '$(srcdir)/partclone.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_chkimg-partclone.Tpo $(DEPDIR)/partclone_chkimg-partclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='partclone.c' object='partclone_chkimg-partclone.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_chkimg_CFLAGS) $(CFLAGS) -c -o partclone_chkimg-partclone.obj `if test -f 'partclone.c'; then $(CYGPATH_W) 'partclone.c'; else $(CYGPATH_W) '$(srcdir)/partclone.c'; fi` partclone_chkimg-progress.o: progress.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_chkimg_CFLAGS) $(CFLAGS) -MT partclone_chkimg-progress.o -MD -MP -MF $(DEPDIR)/partclone_chkimg-progress.Tpo -c -o partclone_chkimg-progress.o `test -f 'progress.c' || echo '$(srcdir)/'`progress.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_chkimg-progress.Tpo $(DEPDIR)/partclone_chkimg-progress.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='progress.c' object='partclone_chkimg-progress.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_chkimg_CFLAGS) $(CFLAGS) -c -o partclone_chkimg-progress.o `test -f 'progress.c' || echo '$(srcdir)/'`progress.c partclone_chkimg-progress.obj: progress.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_chkimg_CFLAGS) $(CFLAGS) -MT partclone_chkimg-progress.obj -MD -MP -MF $(DEPDIR)/partclone_chkimg-progress.Tpo -c -o partclone_chkimg-progress.obj `if test -f 'progress.c'; then $(CYGPATH_W) 'progress.c'; else $(CYGPATH_W) '$(srcdir)/progress.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_chkimg-progress.Tpo $(DEPDIR)/partclone_chkimg-progress.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='progress.c' object='partclone_chkimg-progress.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_chkimg_CFLAGS) $(CFLAGS) -c -o partclone_chkimg-progress.obj `if test -f 'progress.c'; then $(CYGPATH_W) 'progress.c'; else $(CYGPATH_W) '$(srcdir)/progress.c'; fi` partclone_chkimg-ddclone.o: ddclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_chkimg_CFLAGS) $(CFLAGS) -MT partclone_chkimg-ddclone.o -MD -MP -MF $(DEPDIR)/partclone_chkimg-ddclone.Tpo -c -o partclone_chkimg-ddclone.o `test -f 'ddclone.c' || echo '$(srcdir)/'`ddclone.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_chkimg-ddclone.Tpo $(DEPDIR)/partclone_chkimg-ddclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ddclone.c' object='partclone_chkimg-ddclone.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_chkimg_CFLAGS) $(CFLAGS) -c -o partclone_chkimg-ddclone.o `test -f 'ddclone.c' || echo '$(srcdir)/'`ddclone.c partclone_chkimg-ddclone.obj: ddclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_chkimg_CFLAGS) $(CFLAGS) -MT partclone_chkimg-ddclone.obj -MD -MP -MF $(DEPDIR)/partclone_chkimg-ddclone.Tpo -c -o partclone_chkimg-ddclone.obj `if test -f 'ddclone.c'; then $(CYGPATH_W) 'ddclone.c'; else $(CYGPATH_W) '$(srcdir)/ddclone.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_chkimg-ddclone.Tpo $(DEPDIR)/partclone_chkimg-ddclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ddclone.c' object='partclone_chkimg-ddclone.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_chkimg_CFLAGS) $(CFLAGS) -c -o partclone_chkimg-ddclone.obj `if test -f 'ddclone.c'; then $(CYGPATH_W) 'ddclone.c'; else $(CYGPATH_W) '$(srcdir)/ddclone.c'; fi` partclone_dd-main.o: main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_dd_CFLAGS) $(CFLAGS) -MT partclone_dd-main.o -MD -MP -MF $(DEPDIR)/partclone_dd-main.Tpo -c -o partclone_dd-main.o `test -f 'main.c' || echo '$(srcdir)/'`main.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_dd-main.Tpo $(DEPDIR)/partclone_dd-main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='main.c' object='partclone_dd-main.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_dd_CFLAGS) $(CFLAGS) -c -o partclone_dd-main.o `test -f 'main.c' || echo '$(srcdir)/'`main.c partclone_dd-main.obj: main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_dd_CFLAGS) $(CFLAGS) -MT partclone_dd-main.obj -MD -MP -MF $(DEPDIR)/partclone_dd-main.Tpo -c -o partclone_dd-main.obj `if test -f 'main.c'; then $(CYGPATH_W) 'main.c'; else $(CYGPATH_W) '$(srcdir)/main.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_dd-main.Tpo $(DEPDIR)/partclone_dd-main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='main.c' object='partclone_dd-main.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_dd_CFLAGS) $(CFLAGS) -c -o partclone_dd-main.obj `if test -f 'main.c'; then $(CYGPATH_W) 'main.c'; else $(CYGPATH_W) '$(srcdir)/main.c'; fi` partclone_dd-partclone.o: partclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_dd_CFLAGS) $(CFLAGS) -MT partclone_dd-partclone.o -MD -MP -MF $(DEPDIR)/partclone_dd-partclone.Tpo -c -o partclone_dd-partclone.o `test -f 'partclone.c' || echo '$(srcdir)/'`partclone.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_dd-partclone.Tpo $(DEPDIR)/partclone_dd-partclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='partclone.c' object='partclone_dd-partclone.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_dd_CFLAGS) $(CFLAGS) -c -o partclone_dd-partclone.o `test -f 'partclone.c' || echo '$(srcdir)/'`partclone.c partclone_dd-partclone.obj: partclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_dd_CFLAGS) $(CFLAGS) -MT partclone_dd-partclone.obj -MD -MP -MF $(DEPDIR)/partclone_dd-partclone.Tpo -c -o partclone_dd-partclone.obj `if test -f 'partclone.c'; then $(CYGPATH_W) 'partclone.c'; else $(CYGPATH_W) '$(srcdir)/partclone.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_dd-partclone.Tpo $(DEPDIR)/partclone_dd-partclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='partclone.c' object='partclone_dd-partclone.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_dd_CFLAGS) $(CFLAGS) -c -o partclone_dd-partclone.obj `if test -f 'partclone.c'; then $(CYGPATH_W) 'partclone.c'; else $(CYGPATH_W) '$(srcdir)/partclone.c'; fi` partclone_dd-progress.o: progress.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_dd_CFLAGS) $(CFLAGS) -MT partclone_dd-progress.o -MD -MP -MF $(DEPDIR)/partclone_dd-progress.Tpo -c -o partclone_dd-progress.o `test -f 'progress.c' || echo '$(srcdir)/'`progress.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_dd-progress.Tpo $(DEPDIR)/partclone_dd-progress.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='progress.c' object='partclone_dd-progress.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_dd_CFLAGS) $(CFLAGS) -c -o partclone_dd-progress.o `test -f 'progress.c' || echo '$(srcdir)/'`progress.c partclone_dd-progress.obj: progress.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_dd_CFLAGS) $(CFLAGS) -MT partclone_dd-progress.obj -MD -MP -MF $(DEPDIR)/partclone_dd-progress.Tpo -c -o partclone_dd-progress.obj `if test -f 'progress.c'; then $(CYGPATH_W) 'progress.c'; else $(CYGPATH_W) '$(srcdir)/progress.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_dd-progress.Tpo $(DEPDIR)/partclone_dd-progress.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='progress.c' object='partclone_dd-progress.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_dd_CFLAGS) $(CFLAGS) -c -o partclone_dd-progress.obj `if test -f 'progress.c'; then $(CYGPATH_W) 'progress.c'; else $(CYGPATH_W) '$(srcdir)/progress.c'; fi` partclone_dd-ddclone.o: ddclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_dd_CFLAGS) $(CFLAGS) -MT partclone_dd-ddclone.o -MD -MP -MF $(DEPDIR)/partclone_dd-ddclone.Tpo -c -o partclone_dd-ddclone.o `test -f 'ddclone.c' || echo '$(srcdir)/'`ddclone.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_dd-ddclone.Tpo $(DEPDIR)/partclone_dd-ddclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ddclone.c' object='partclone_dd-ddclone.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_dd_CFLAGS) $(CFLAGS) -c -o partclone_dd-ddclone.o `test -f 'ddclone.c' || echo '$(srcdir)/'`ddclone.c partclone_dd-ddclone.obj: ddclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_dd_CFLAGS) $(CFLAGS) -MT partclone_dd-ddclone.obj -MD -MP -MF $(DEPDIR)/partclone_dd-ddclone.Tpo -c -o partclone_dd-ddclone.obj `if test -f 'ddclone.c'; then $(CYGPATH_W) 'ddclone.c'; else $(CYGPATH_W) '$(srcdir)/ddclone.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_dd-ddclone.Tpo $(DEPDIR)/partclone_dd-ddclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ddclone.c' object='partclone_dd-ddclone.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_dd_CFLAGS) $(CFLAGS) -c -o partclone_dd-ddclone.obj `if test -f 'ddclone.c'; then $(CYGPATH_W) 'ddclone.c'; else $(CYGPATH_W) '$(srcdir)/ddclone.c'; fi` partclone_exfat-main.o: main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_exfat_CFLAGS) $(CFLAGS) -MT partclone_exfat-main.o -MD -MP -MF $(DEPDIR)/partclone_exfat-main.Tpo -c -o partclone_exfat-main.o `test -f 'main.c' || echo '$(srcdir)/'`main.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_exfat-main.Tpo $(DEPDIR)/partclone_exfat-main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='main.c' object='partclone_exfat-main.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_exfat_CFLAGS) $(CFLAGS) -c -o partclone_exfat-main.o `test -f 'main.c' || echo '$(srcdir)/'`main.c partclone_exfat-main.obj: main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_exfat_CFLAGS) $(CFLAGS) -MT partclone_exfat-main.obj -MD -MP -MF $(DEPDIR)/partclone_exfat-main.Tpo -c -o partclone_exfat-main.obj `if test -f 'main.c'; then $(CYGPATH_W) 'main.c'; else $(CYGPATH_W) '$(srcdir)/main.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_exfat-main.Tpo $(DEPDIR)/partclone_exfat-main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='main.c' object='partclone_exfat-main.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_exfat_CFLAGS) $(CFLAGS) -c -o partclone_exfat-main.obj `if test -f 'main.c'; then $(CYGPATH_W) 'main.c'; else $(CYGPATH_W) '$(srcdir)/main.c'; fi` partclone_exfat-partclone.o: partclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_exfat_CFLAGS) $(CFLAGS) -MT partclone_exfat-partclone.o -MD -MP -MF $(DEPDIR)/partclone_exfat-partclone.Tpo -c -o partclone_exfat-partclone.o `test -f 'partclone.c' || echo '$(srcdir)/'`partclone.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_exfat-partclone.Tpo $(DEPDIR)/partclone_exfat-partclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='partclone.c' object='partclone_exfat-partclone.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_exfat_CFLAGS) $(CFLAGS) -c -o partclone_exfat-partclone.o `test -f 'partclone.c' || echo '$(srcdir)/'`partclone.c partclone_exfat-partclone.obj: partclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_exfat_CFLAGS) $(CFLAGS) -MT partclone_exfat-partclone.obj -MD -MP -MF $(DEPDIR)/partclone_exfat-partclone.Tpo -c -o partclone_exfat-partclone.obj `if test -f 'partclone.c'; then $(CYGPATH_W) 'partclone.c'; else $(CYGPATH_W) '$(srcdir)/partclone.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_exfat-partclone.Tpo $(DEPDIR)/partclone_exfat-partclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='partclone.c' object='partclone_exfat-partclone.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_exfat_CFLAGS) $(CFLAGS) -c -o partclone_exfat-partclone.obj `if test -f 'partclone.c'; then $(CYGPATH_W) 'partclone.c'; else $(CYGPATH_W) '$(srcdir)/partclone.c'; fi` partclone_exfat-progress.o: progress.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_exfat_CFLAGS) $(CFLAGS) -MT partclone_exfat-progress.o -MD -MP -MF $(DEPDIR)/partclone_exfat-progress.Tpo -c -o partclone_exfat-progress.o `test -f 'progress.c' || echo '$(srcdir)/'`progress.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_exfat-progress.Tpo $(DEPDIR)/partclone_exfat-progress.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='progress.c' object='partclone_exfat-progress.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_exfat_CFLAGS) $(CFLAGS) -c -o partclone_exfat-progress.o `test -f 'progress.c' || echo '$(srcdir)/'`progress.c partclone_exfat-progress.obj: progress.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_exfat_CFLAGS) $(CFLAGS) -MT partclone_exfat-progress.obj -MD -MP -MF $(DEPDIR)/partclone_exfat-progress.Tpo -c -o partclone_exfat-progress.obj `if test -f 'progress.c'; then $(CYGPATH_W) 'progress.c'; else $(CYGPATH_W) '$(srcdir)/progress.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_exfat-progress.Tpo $(DEPDIR)/partclone_exfat-progress.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='progress.c' object='partclone_exfat-progress.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_exfat_CFLAGS) $(CFLAGS) -c -o partclone_exfat-progress.obj `if test -f 'progress.c'; then $(CYGPATH_W) 'progress.c'; else $(CYGPATH_W) '$(srcdir)/progress.c'; fi` partclone_exfat-exfatclone.o: exfatclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_exfat_CFLAGS) $(CFLAGS) -MT partclone_exfat-exfatclone.o -MD -MP -MF $(DEPDIR)/partclone_exfat-exfatclone.Tpo -c -o partclone_exfat-exfatclone.o `test -f 'exfatclone.c' || echo '$(srcdir)/'`exfatclone.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_exfat-exfatclone.Tpo $(DEPDIR)/partclone_exfat-exfatclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='exfatclone.c' object='partclone_exfat-exfatclone.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_exfat_CFLAGS) $(CFLAGS) -c -o partclone_exfat-exfatclone.o `test -f 'exfatclone.c' || echo '$(srcdir)/'`exfatclone.c partclone_exfat-exfatclone.obj: exfatclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_exfat_CFLAGS) $(CFLAGS) -MT partclone_exfat-exfatclone.obj -MD -MP -MF $(DEPDIR)/partclone_exfat-exfatclone.Tpo -c -o partclone_exfat-exfatclone.obj `if test -f 'exfatclone.c'; then $(CYGPATH_W) 'exfatclone.c'; else $(CYGPATH_W) '$(srcdir)/exfatclone.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_exfat-exfatclone.Tpo $(DEPDIR)/partclone_exfat-exfatclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='exfatclone.c' object='partclone_exfat-exfatclone.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_exfat_CFLAGS) $(CFLAGS) -c -o partclone_exfat-exfatclone.obj `if test -f 'exfatclone.c'; then $(CYGPATH_W) 'exfatclone.c'; else $(CYGPATH_W) '$(srcdir)/exfatclone.c'; fi` exfat/partclone_exfat-cluster.o: exfat/cluster.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_exfat_CFLAGS) $(CFLAGS) -MT exfat/partclone_exfat-cluster.o -MD -MP -MF exfat/$(DEPDIR)/partclone_exfat-cluster.Tpo -c -o exfat/partclone_exfat-cluster.o `test -f 'exfat/cluster.c' || echo '$(srcdir)/'`exfat/cluster.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) exfat/$(DEPDIR)/partclone_exfat-cluster.Tpo exfat/$(DEPDIR)/partclone_exfat-cluster.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='exfat/cluster.c' object='exfat/partclone_exfat-cluster.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_exfat_CFLAGS) $(CFLAGS) -c -o exfat/partclone_exfat-cluster.o `test -f 'exfat/cluster.c' || echo '$(srcdir)/'`exfat/cluster.c exfat/partclone_exfat-cluster.obj: exfat/cluster.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_exfat_CFLAGS) $(CFLAGS) -MT exfat/partclone_exfat-cluster.obj -MD -MP -MF exfat/$(DEPDIR)/partclone_exfat-cluster.Tpo -c -o exfat/partclone_exfat-cluster.obj `if test -f 'exfat/cluster.c'; then $(CYGPATH_W) 'exfat/cluster.c'; else $(CYGPATH_W) '$(srcdir)/exfat/cluster.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) exfat/$(DEPDIR)/partclone_exfat-cluster.Tpo exfat/$(DEPDIR)/partclone_exfat-cluster.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='exfat/cluster.c' object='exfat/partclone_exfat-cluster.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_exfat_CFLAGS) $(CFLAGS) -c -o exfat/partclone_exfat-cluster.obj `if test -f 'exfat/cluster.c'; then $(CYGPATH_W) 'exfat/cluster.c'; else $(CYGPATH_W) '$(srcdir)/exfat/cluster.c'; fi` exfat/partclone_exfat-utf.o: exfat/utf.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_exfat_CFLAGS) $(CFLAGS) -MT exfat/partclone_exfat-utf.o -MD -MP -MF exfat/$(DEPDIR)/partclone_exfat-utf.Tpo -c -o exfat/partclone_exfat-utf.o `test -f 'exfat/utf.c' || echo '$(srcdir)/'`exfat/utf.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) exfat/$(DEPDIR)/partclone_exfat-utf.Tpo exfat/$(DEPDIR)/partclone_exfat-utf.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='exfat/utf.c' object='exfat/partclone_exfat-utf.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_exfat_CFLAGS) $(CFLAGS) -c -o exfat/partclone_exfat-utf.o `test -f 'exfat/utf.c' || echo '$(srcdir)/'`exfat/utf.c exfat/partclone_exfat-utf.obj: exfat/utf.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_exfat_CFLAGS) $(CFLAGS) -MT exfat/partclone_exfat-utf.obj -MD -MP -MF exfat/$(DEPDIR)/partclone_exfat-utf.Tpo -c -o exfat/partclone_exfat-utf.obj `if test -f 'exfat/utf.c'; then $(CYGPATH_W) 'exfat/utf.c'; else $(CYGPATH_W) '$(srcdir)/exfat/utf.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) exfat/$(DEPDIR)/partclone_exfat-utf.Tpo exfat/$(DEPDIR)/partclone_exfat-utf.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='exfat/utf.c' object='exfat/partclone_exfat-utf.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_exfat_CFLAGS) $(CFLAGS) -c -o exfat/partclone_exfat-utf.obj `if test -f 'exfat/utf.c'; then $(CYGPATH_W) 'exfat/utf.c'; else $(CYGPATH_W) '$(srcdir)/exfat/utf.c'; fi` exfat/partclone_exfat-utils.o: exfat/utils.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_exfat_CFLAGS) $(CFLAGS) -MT exfat/partclone_exfat-utils.o -MD -MP -MF exfat/$(DEPDIR)/partclone_exfat-utils.Tpo -c -o exfat/partclone_exfat-utils.o `test -f 'exfat/utils.c' || echo '$(srcdir)/'`exfat/utils.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) exfat/$(DEPDIR)/partclone_exfat-utils.Tpo exfat/$(DEPDIR)/partclone_exfat-utils.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='exfat/utils.c' object='exfat/partclone_exfat-utils.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_exfat_CFLAGS) $(CFLAGS) -c -o exfat/partclone_exfat-utils.o `test -f 'exfat/utils.c' || echo '$(srcdir)/'`exfat/utils.c exfat/partclone_exfat-utils.obj: exfat/utils.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_exfat_CFLAGS) $(CFLAGS) -MT exfat/partclone_exfat-utils.obj -MD -MP -MF exfat/$(DEPDIR)/partclone_exfat-utils.Tpo -c -o exfat/partclone_exfat-utils.obj `if test -f 'exfat/utils.c'; then $(CYGPATH_W) 'exfat/utils.c'; else $(CYGPATH_W) '$(srcdir)/exfat/utils.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) exfat/$(DEPDIR)/partclone_exfat-utils.Tpo exfat/$(DEPDIR)/partclone_exfat-utils.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='exfat/utils.c' object='exfat/partclone_exfat-utils.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_exfat_CFLAGS) $(CFLAGS) -c -o exfat/partclone_exfat-utils.obj `if test -f 'exfat/utils.c'; then $(CYGPATH_W) 'exfat/utils.c'; else $(CYGPATH_W) '$(srcdir)/exfat/utils.c'; fi` exfat/partclone_exfat-lookup.o: exfat/lookup.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_exfat_CFLAGS) $(CFLAGS) -MT exfat/partclone_exfat-lookup.o -MD -MP -MF exfat/$(DEPDIR)/partclone_exfat-lookup.Tpo -c -o exfat/partclone_exfat-lookup.o `test -f 'exfat/lookup.c' || echo '$(srcdir)/'`exfat/lookup.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) exfat/$(DEPDIR)/partclone_exfat-lookup.Tpo exfat/$(DEPDIR)/partclone_exfat-lookup.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='exfat/lookup.c' object='exfat/partclone_exfat-lookup.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_exfat_CFLAGS) $(CFLAGS) -c -o exfat/partclone_exfat-lookup.o `test -f 'exfat/lookup.c' || echo '$(srcdir)/'`exfat/lookup.c exfat/partclone_exfat-lookup.obj: exfat/lookup.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_exfat_CFLAGS) $(CFLAGS) -MT exfat/partclone_exfat-lookup.obj -MD -MP -MF exfat/$(DEPDIR)/partclone_exfat-lookup.Tpo -c -o exfat/partclone_exfat-lookup.obj `if test -f 'exfat/lookup.c'; then $(CYGPATH_W) 'exfat/lookup.c'; else $(CYGPATH_W) '$(srcdir)/exfat/lookup.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) exfat/$(DEPDIR)/partclone_exfat-lookup.Tpo exfat/$(DEPDIR)/partclone_exfat-lookup.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='exfat/lookup.c' object='exfat/partclone_exfat-lookup.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_exfat_CFLAGS) $(CFLAGS) -c -o exfat/partclone_exfat-lookup.obj `if test -f 'exfat/lookup.c'; then $(CYGPATH_W) 'exfat/lookup.c'; else $(CYGPATH_W) '$(srcdir)/exfat/lookup.c'; fi` exfat/partclone_exfat-io.o: exfat/io.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_exfat_CFLAGS) $(CFLAGS) -MT exfat/partclone_exfat-io.o -MD -MP -MF exfat/$(DEPDIR)/partclone_exfat-io.Tpo -c -o exfat/partclone_exfat-io.o `test -f 'exfat/io.c' || echo '$(srcdir)/'`exfat/io.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) exfat/$(DEPDIR)/partclone_exfat-io.Tpo exfat/$(DEPDIR)/partclone_exfat-io.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='exfat/io.c' object='exfat/partclone_exfat-io.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_exfat_CFLAGS) $(CFLAGS) -c -o exfat/partclone_exfat-io.o `test -f 'exfat/io.c' || echo '$(srcdir)/'`exfat/io.c exfat/partclone_exfat-io.obj: exfat/io.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_exfat_CFLAGS) $(CFLAGS) -MT exfat/partclone_exfat-io.obj -MD -MP -MF exfat/$(DEPDIR)/partclone_exfat-io.Tpo -c -o exfat/partclone_exfat-io.obj `if test -f 'exfat/io.c'; then $(CYGPATH_W) 'exfat/io.c'; else $(CYGPATH_W) '$(srcdir)/exfat/io.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) exfat/$(DEPDIR)/partclone_exfat-io.Tpo exfat/$(DEPDIR)/partclone_exfat-io.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='exfat/io.c' object='exfat/partclone_exfat-io.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_exfat_CFLAGS) $(CFLAGS) -c -o exfat/partclone_exfat-io.obj `if test -f 'exfat/io.c'; then $(CYGPATH_W) 'exfat/io.c'; else $(CYGPATH_W) '$(srcdir)/exfat/io.c'; fi` exfat/partclone_exfat-log.o: exfat/log.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_exfat_CFLAGS) $(CFLAGS) -MT exfat/partclone_exfat-log.o -MD -MP -MF exfat/$(DEPDIR)/partclone_exfat-log.Tpo -c -o exfat/partclone_exfat-log.o `test -f 'exfat/log.c' || echo '$(srcdir)/'`exfat/log.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) exfat/$(DEPDIR)/partclone_exfat-log.Tpo exfat/$(DEPDIR)/partclone_exfat-log.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='exfat/log.c' object='exfat/partclone_exfat-log.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_exfat_CFLAGS) $(CFLAGS) -c -o exfat/partclone_exfat-log.o `test -f 'exfat/log.c' || echo '$(srcdir)/'`exfat/log.c exfat/partclone_exfat-log.obj: exfat/log.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_exfat_CFLAGS) $(CFLAGS) -MT exfat/partclone_exfat-log.obj -MD -MP -MF exfat/$(DEPDIR)/partclone_exfat-log.Tpo -c -o exfat/partclone_exfat-log.obj `if test -f 'exfat/log.c'; then $(CYGPATH_W) 'exfat/log.c'; else $(CYGPATH_W) '$(srcdir)/exfat/log.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) exfat/$(DEPDIR)/partclone_exfat-log.Tpo exfat/$(DEPDIR)/partclone_exfat-log.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='exfat/log.c' object='exfat/partclone_exfat-log.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_exfat_CFLAGS) $(CFLAGS) -c -o exfat/partclone_exfat-log.obj `if test -f 'exfat/log.c'; then $(CYGPATH_W) 'exfat/log.c'; else $(CYGPATH_W) '$(srcdir)/exfat/log.c'; fi` exfat/partclone_exfat-node.o: exfat/node.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_exfat_CFLAGS) $(CFLAGS) -MT exfat/partclone_exfat-node.o -MD -MP -MF exfat/$(DEPDIR)/partclone_exfat-node.Tpo -c -o exfat/partclone_exfat-node.o `test -f 'exfat/node.c' || echo '$(srcdir)/'`exfat/node.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) exfat/$(DEPDIR)/partclone_exfat-node.Tpo exfat/$(DEPDIR)/partclone_exfat-node.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='exfat/node.c' object='exfat/partclone_exfat-node.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_exfat_CFLAGS) $(CFLAGS) -c -o exfat/partclone_exfat-node.o `test -f 'exfat/node.c' || echo '$(srcdir)/'`exfat/node.c exfat/partclone_exfat-node.obj: exfat/node.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_exfat_CFLAGS) $(CFLAGS) -MT exfat/partclone_exfat-node.obj -MD -MP -MF exfat/$(DEPDIR)/partclone_exfat-node.Tpo -c -o exfat/partclone_exfat-node.obj `if test -f 'exfat/node.c'; then $(CYGPATH_W) 'exfat/node.c'; else $(CYGPATH_W) '$(srcdir)/exfat/node.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) exfat/$(DEPDIR)/partclone_exfat-node.Tpo exfat/$(DEPDIR)/partclone_exfat-node.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='exfat/node.c' object='exfat/partclone_exfat-node.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_exfat_CFLAGS) $(CFLAGS) -c -o exfat/partclone_exfat-node.obj `if test -f 'exfat/node.c'; then $(CYGPATH_W) 'exfat/node.c'; else $(CYGPATH_W) '$(srcdir)/exfat/node.c'; fi` exfat/partclone_exfat-mount.o: exfat/mount.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_exfat_CFLAGS) $(CFLAGS) -MT exfat/partclone_exfat-mount.o -MD -MP -MF exfat/$(DEPDIR)/partclone_exfat-mount.Tpo -c -o exfat/partclone_exfat-mount.o `test -f 'exfat/mount.c' || echo '$(srcdir)/'`exfat/mount.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) exfat/$(DEPDIR)/partclone_exfat-mount.Tpo exfat/$(DEPDIR)/partclone_exfat-mount.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='exfat/mount.c' object='exfat/partclone_exfat-mount.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_exfat_CFLAGS) $(CFLAGS) -c -o exfat/partclone_exfat-mount.o `test -f 'exfat/mount.c' || echo '$(srcdir)/'`exfat/mount.c exfat/partclone_exfat-mount.obj: exfat/mount.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_exfat_CFLAGS) $(CFLAGS) -MT exfat/partclone_exfat-mount.obj -MD -MP -MF exfat/$(DEPDIR)/partclone_exfat-mount.Tpo -c -o exfat/partclone_exfat-mount.obj `if test -f 'exfat/mount.c'; then $(CYGPATH_W) 'exfat/mount.c'; else $(CYGPATH_W) '$(srcdir)/exfat/mount.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) exfat/$(DEPDIR)/partclone_exfat-mount.Tpo exfat/$(DEPDIR)/partclone_exfat-mount.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='exfat/mount.c' object='exfat/partclone_exfat-mount.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_exfat_CFLAGS) $(CFLAGS) -c -o exfat/partclone_exfat-mount.obj `if test -f 'exfat/mount.c'; then $(CYGPATH_W) 'exfat/mount.c'; else $(CYGPATH_W) '$(srcdir)/exfat/mount.c'; fi` exfat/partclone_exfat-time.o: exfat/time.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_exfat_CFLAGS) $(CFLAGS) -MT exfat/partclone_exfat-time.o -MD -MP -MF exfat/$(DEPDIR)/partclone_exfat-time.Tpo -c -o exfat/partclone_exfat-time.o `test -f 'exfat/time.c' || echo '$(srcdir)/'`exfat/time.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) exfat/$(DEPDIR)/partclone_exfat-time.Tpo exfat/$(DEPDIR)/partclone_exfat-time.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='exfat/time.c' object='exfat/partclone_exfat-time.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_exfat_CFLAGS) $(CFLAGS) -c -o exfat/partclone_exfat-time.o `test -f 'exfat/time.c' || echo '$(srcdir)/'`exfat/time.c exfat/partclone_exfat-time.obj: exfat/time.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_exfat_CFLAGS) $(CFLAGS) -MT exfat/partclone_exfat-time.obj -MD -MP -MF exfat/$(DEPDIR)/partclone_exfat-time.Tpo -c -o exfat/partclone_exfat-time.obj `if test -f 'exfat/time.c'; then $(CYGPATH_W) 'exfat/time.c'; else $(CYGPATH_W) '$(srcdir)/exfat/time.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) exfat/$(DEPDIR)/partclone_exfat-time.Tpo exfat/$(DEPDIR)/partclone_exfat-time.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='exfat/time.c' object='exfat/partclone_exfat-time.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_exfat_CFLAGS) $(CFLAGS) -c -o exfat/partclone_exfat-time.obj `if test -f 'exfat/time.c'; then $(CYGPATH_W) 'exfat/time.c'; else $(CYGPATH_W) '$(srcdir)/exfat/time.c'; fi` partclone_extfs-main.o: main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_extfs_CFLAGS) $(CFLAGS) -MT partclone_extfs-main.o -MD -MP -MF $(DEPDIR)/partclone_extfs-main.Tpo -c -o partclone_extfs-main.o `test -f 'main.c' || echo '$(srcdir)/'`main.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_extfs-main.Tpo $(DEPDIR)/partclone_extfs-main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='main.c' object='partclone_extfs-main.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_extfs_CFLAGS) $(CFLAGS) -c -o partclone_extfs-main.o `test -f 'main.c' || echo '$(srcdir)/'`main.c partclone_extfs-main.obj: main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_extfs_CFLAGS) $(CFLAGS) -MT partclone_extfs-main.obj -MD -MP -MF $(DEPDIR)/partclone_extfs-main.Tpo -c -o partclone_extfs-main.obj `if test -f 'main.c'; then $(CYGPATH_W) 'main.c'; else $(CYGPATH_W) '$(srcdir)/main.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_extfs-main.Tpo $(DEPDIR)/partclone_extfs-main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='main.c' object='partclone_extfs-main.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_extfs_CFLAGS) $(CFLAGS) -c -o partclone_extfs-main.obj `if test -f 'main.c'; then $(CYGPATH_W) 'main.c'; else $(CYGPATH_W) '$(srcdir)/main.c'; fi` partclone_extfs-partclone.o: partclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_extfs_CFLAGS) $(CFLAGS) -MT partclone_extfs-partclone.o -MD -MP -MF $(DEPDIR)/partclone_extfs-partclone.Tpo -c -o partclone_extfs-partclone.o `test -f 'partclone.c' || echo '$(srcdir)/'`partclone.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_extfs-partclone.Tpo $(DEPDIR)/partclone_extfs-partclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='partclone.c' object='partclone_extfs-partclone.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_extfs_CFLAGS) $(CFLAGS) -c -o partclone_extfs-partclone.o `test -f 'partclone.c' || echo '$(srcdir)/'`partclone.c partclone_extfs-partclone.obj: partclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_extfs_CFLAGS) $(CFLAGS) -MT partclone_extfs-partclone.obj -MD -MP -MF $(DEPDIR)/partclone_extfs-partclone.Tpo -c -o partclone_extfs-partclone.obj `if test -f 'partclone.c'; then $(CYGPATH_W) 'partclone.c'; else $(CYGPATH_W) '$(srcdir)/partclone.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_extfs-partclone.Tpo $(DEPDIR)/partclone_extfs-partclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='partclone.c' object='partclone_extfs-partclone.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_extfs_CFLAGS) $(CFLAGS) -c -o partclone_extfs-partclone.obj `if test -f 'partclone.c'; then $(CYGPATH_W) 'partclone.c'; else $(CYGPATH_W) '$(srcdir)/partclone.c'; fi` partclone_extfs-progress.o: progress.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_extfs_CFLAGS) $(CFLAGS) -MT partclone_extfs-progress.o -MD -MP -MF $(DEPDIR)/partclone_extfs-progress.Tpo -c -o partclone_extfs-progress.o `test -f 'progress.c' || echo '$(srcdir)/'`progress.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_extfs-progress.Tpo $(DEPDIR)/partclone_extfs-progress.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='progress.c' object='partclone_extfs-progress.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_extfs_CFLAGS) $(CFLAGS) -c -o partclone_extfs-progress.o `test -f 'progress.c' || echo '$(srcdir)/'`progress.c partclone_extfs-progress.obj: progress.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_extfs_CFLAGS) $(CFLAGS) -MT partclone_extfs-progress.obj -MD -MP -MF $(DEPDIR)/partclone_extfs-progress.Tpo -c -o partclone_extfs-progress.obj `if test -f 'progress.c'; then $(CYGPATH_W) 'progress.c'; else $(CYGPATH_W) '$(srcdir)/progress.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_extfs-progress.Tpo $(DEPDIR)/partclone_extfs-progress.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='progress.c' object='partclone_extfs-progress.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_extfs_CFLAGS) $(CFLAGS) -c -o partclone_extfs-progress.obj `if test -f 'progress.c'; then $(CYGPATH_W) 'progress.c'; else $(CYGPATH_W) '$(srcdir)/progress.c'; fi` partclone_extfs-extfsclone.o: extfsclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_extfs_CFLAGS) $(CFLAGS) -MT partclone_extfs-extfsclone.o -MD -MP -MF $(DEPDIR)/partclone_extfs-extfsclone.Tpo -c -o partclone_extfs-extfsclone.o `test -f 'extfsclone.c' || echo '$(srcdir)/'`extfsclone.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_extfs-extfsclone.Tpo $(DEPDIR)/partclone_extfs-extfsclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='extfsclone.c' object='partclone_extfs-extfsclone.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_extfs_CFLAGS) $(CFLAGS) -c -o partclone_extfs-extfsclone.o `test -f 'extfsclone.c' || echo '$(srcdir)/'`extfsclone.c partclone_extfs-extfsclone.obj: extfsclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_extfs_CFLAGS) $(CFLAGS) -MT partclone_extfs-extfsclone.obj -MD -MP -MF $(DEPDIR)/partclone_extfs-extfsclone.Tpo -c -o partclone_extfs-extfsclone.obj `if test -f 'extfsclone.c'; then $(CYGPATH_W) 'extfsclone.c'; else $(CYGPATH_W) '$(srcdir)/extfsclone.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_extfs-extfsclone.Tpo $(DEPDIR)/partclone_extfs-extfsclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='extfsclone.c' object='partclone_extfs-extfsclone.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_extfs_CFLAGS) $(CFLAGS) -c -o partclone_extfs-extfsclone.obj `if test -f 'extfsclone.c'; then $(CYGPATH_W) 'extfsclone.c'; else $(CYGPATH_W) '$(srcdir)/extfsclone.c'; fi` partclone_f2fs-main.o: main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_f2fs_CFLAGS) $(CFLAGS) -MT partclone_f2fs-main.o -MD -MP -MF $(DEPDIR)/partclone_f2fs-main.Tpo -c -o partclone_f2fs-main.o `test -f 'main.c' || echo '$(srcdir)/'`main.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_f2fs-main.Tpo $(DEPDIR)/partclone_f2fs-main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='main.c' object='partclone_f2fs-main.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_f2fs_CFLAGS) $(CFLAGS) -c -o partclone_f2fs-main.o `test -f 'main.c' || echo '$(srcdir)/'`main.c partclone_f2fs-main.obj: main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_f2fs_CFLAGS) $(CFLAGS) -MT partclone_f2fs-main.obj -MD -MP -MF $(DEPDIR)/partclone_f2fs-main.Tpo -c -o partclone_f2fs-main.obj `if test -f 'main.c'; then $(CYGPATH_W) 'main.c'; else $(CYGPATH_W) '$(srcdir)/main.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_f2fs-main.Tpo $(DEPDIR)/partclone_f2fs-main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='main.c' object='partclone_f2fs-main.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_f2fs_CFLAGS) $(CFLAGS) -c -o partclone_f2fs-main.obj `if test -f 'main.c'; then $(CYGPATH_W) 'main.c'; else $(CYGPATH_W) '$(srcdir)/main.c'; fi` partclone_f2fs-partclone.o: partclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_f2fs_CFLAGS) $(CFLAGS) -MT partclone_f2fs-partclone.o -MD -MP -MF $(DEPDIR)/partclone_f2fs-partclone.Tpo -c -o partclone_f2fs-partclone.o `test -f 'partclone.c' || echo '$(srcdir)/'`partclone.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_f2fs-partclone.Tpo $(DEPDIR)/partclone_f2fs-partclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='partclone.c' object='partclone_f2fs-partclone.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_f2fs_CFLAGS) $(CFLAGS) -c -o partclone_f2fs-partclone.o `test -f 'partclone.c' || echo '$(srcdir)/'`partclone.c partclone_f2fs-partclone.obj: partclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_f2fs_CFLAGS) $(CFLAGS) -MT partclone_f2fs-partclone.obj -MD -MP -MF $(DEPDIR)/partclone_f2fs-partclone.Tpo -c -o partclone_f2fs-partclone.obj `if test -f 'partclone.c'; then $(CYGPATH_W) 'partclone.c'; else $(CYGPATH_W) '$(srcdir)/partclone.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_f2fs-partclone.Tpo $(DEPDIR)/partclone_f2fs-partclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='partclone.c' object='partclone_f2fs-partclone.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_f2fs_CFLAGS) $(CFLAGS) -c -o partclone_f2fs-partclone.obj `if test -f 'partclone.c'; then $(CYGPATH_W) 'partclone.c'; else $(CYGPATH_W) '$(srcdir)/partclone.c'; fi` partclone_f2fs-progress.o: progress.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_f2fs_CFLAGS) $(CFLAGS) -MT partclone_f2fs-progress.o -MD -MP -MF $(DEPDIR)/partclone_f2fs-progress.Tpo -c -o partclone_f2fs-progress.o `test -f 'progress.c' || echo '$(srcdir)/'`progress.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_f2fs-progress.Tpo $(DEPDIR)/partclone_f2fs-progress.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='progress.c' object='partclone_f2fs-progress.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_f2fs_CFLAGS) $(CFLAGS) -c -o partclone_f2fs-progress.o `test -f 'progress.c' || echo '$(srcdir)/'`progress.c partclone_f2fs-progress.obj: progress.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_f2fs_CFLAGS) $(CFLAGS) -MT partclone_f2fs-progress.obj -MD -MP -MF $(DEPDIR)/partclone_f2fs-progress.Tpo -c -o partclone_f2fs-progress.obj `if test -f 'progress.c'; then $(CYGPATH_W) 'progress.c'; else $(CYGPATH_W) '$(srcdir)/progress.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_f2fs-progress.Tpo $(DEPDIR)/partclone_f2fs-progress.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='progress.c' object='partclone_f2fs-progress.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_f2fs_CFLAGS) $(CFLAGS) -c -o partclone_f2fs-progress.obj `if test -f 'progress.c'; then $(CYGPATH_W) 'progress.c'; else $(CYGPATH_W) '$(srcdir)/progress.c'; fi` partclone_f2fs-f2fsclone.o: f2fsclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_f2fs_CFLAGS) $(CFLAGS) -MT partclone_f2fs-f2fsclone.o -MD -MP -MF $(DEPDIR)/partclone_f2fs-f2fsclone.Tpo -c -o partclone_f2fs-f2fsclone.o `test -f 'f2fsclone.c' || echo '$(srcdir)/'`f2fsclone.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_f2fs-f2fsclone.Tpo $(DEPDIR)/partclone_f2fs-f2fsclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='f2fsclone.c' object='partclone_f2fs-f2fsclone.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_f2fs_CFLAGS) $(CFLAGS) -c -o partclone_f2fs-f2fsclone.o `test -f 'f2fsclone.c' || echo '$(srcdir)/'`f2fsclone.c partclone_f2fs-f2fsclone.obj: f2fsclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_f2fs_CFLAGS) $(CFLAGS) -MT partclone_f2fs-f2fsclone.obj -MD -MP -MF $(DEPDIR)/partclone_f2fs-f2fsclone.Tpo -c -o partclone_f2fs-f2fsclone.obj `if test -f 'f2fsclone.c'; then $(CYGPATH_W) 'f2fsclone.c'; else $(CYGPATH_W) '$(srcdir)/f2fsclone.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_f2fs-f2fsclone.Tpo $(DEPDIR)/partclone_f2fs-f2fsclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='f2fsclone.c' object='partclone_f2fs-f2fsclone.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_f2fs_CFLAGS) $(CFLAGS) -c -o partclone_f2fs-f2fsclone.obj `if test -f 'f2fsclone.c'; then $(CYGPATH_W) 'f2fsclone.c'; else $(CYGPATH_W) '$(srcdir)/f2fsclone.c'; fi` f2fs/partclone_f2fs-fsck.o: f2fs/fsck.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_f2fs_CFLAGS) $(CFLAGS) -MT f2fs/partclone_f2fs-fsck.o -MD -MP -MF f2fs/$(DEPDIR)/partclone_f2fs-fsck.Tpo -c -o f2fs/partclone_f2fs-fsck.o `test -f 'f2fs/fsck.c' || echo '$(srcdir)/'`f2fs/fsck.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) f2fs/$(DEPDIR)/partclone_f2fs-fsck.Tpo f2fs/$(DEPDIR)/partclone_f2fs-fsck.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='f2fs/fsck.c' object='f2fs/partclone_f2fs-fsck.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_f2fs_CFLAGS) $(CFLAGS) -c -o f2fs/partclone_f2fs-fsck.o `test -f 'f2fs/fsck.c' || echo '$(srcdir)/'`f2fs/fsck.c f2fs/partclone_f2fs-fsck.obj: f2fs/fsck.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_f2fs_CFLAGS) $(CFLAGS) -MT f2fs/partclone_f2fs-fsck.obj -MD -MP -MF f2fs/$(DEPDIR)/partclone_f2fs-fsck.Tpo -c -o f2fs/partclone_f2fs-fsck.obj `if test -f 'f2fs/fsck.c'; then $(CYGPATH_W) 'f2fs/fsck.c'; else $(CYGPATH_W) '$(srcdir)/f2fs/fsck.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) f2fs/$(DEPDIR)/partclone_f2fs-fsck.Tpo f2fs/$(DEPDIR)/partclone_f2fs-fsck.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='f2fs/fsck.c' object='f2fs/partclone_f2fs-fsck.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_f2fs_CFLAGS) $(CFLAGS) -c -o f2fs/partclone_f2fs-fsck.obj `if test -f 'f2fs/fsck.c'; then $(CYGPATH_W) 'f2fs/fsck.c'; else $(CYGPATH_W) '$(srcdir)/f2fs/fsck.c'; fi` f2fs/partclone_f2fs-libf2fs.o: f2fs/libf2fs.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_f2fs_CFLAGS) $(CFLAGS) -MT f2fs/partclone_f2fs-libf2fs.o -MD -MP -MF f2fs/$(DEPDIR)/partclone_f2fs-libf2fs.Tpo -c -o f2fs/partclone_f2fs-libf2fs.o `test -f 'f2fs/libf2fs.c' || echo '$(srcdir)/'`f2fs/libf2fs.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) f2fs/$(DEPDIR)/partclone_f2fs-libf2fs.Tpo f2fs/$(DEPDIR)/partclone_f2fs-libf2fs.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='f2fs/libf2fs.c' object='f2fs/partclone_f2fs-libf2fs.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_f2fs_CFLAGS) $(CFLAGS) -c -o f2fs/partclone_f2fs-libf2fs.o `test -f 'f2fs/libf2fs.c' || echo '$(srcdir)/'`f2fs/libf2fs.c f2fs/partclone_f2fs-libf2fs.obj: f2fs/libf2fs.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_f2fs_CFLAGS) $(CFLAGS) -MT f2fs/partclone_f2fs-libf2fs.obj -MD -MP -MF f2fs/$(DEPDIR)/partclone_f2fs-libf2fs.Tpo -c -o f2fs/partclone_f2fs-libf2fs.obj `if test -f 'f2fs/libf2fs.c'; then $(CYGPATH_W) 'f2fs/libf2fs.c'; else $(CYGPATH_W) '$(srcdir)/f2fs/libf2fs.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) f2fs/$(DEPDIR)/partclone_f2fs-libf2fs.Tpo f2fs/$(DEPDIR)/partclone_f2fs-libf2fs.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='f2fs/libf2fs.c' object='f2fs/partclone_f2fs-libf2fs.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_f2fs_CFLAGS) $(CFLAGS) -c -o f2fs/partclone_f2fs-libf2fs.obj `if test -f 'f2fs/libf2fs.c'; then $(CYGPATH_W) 'f2fs/libf2fs.c'; else $(CYGPATH_W) '$(srcdir)/f2fs/libf2fs.c'; fi` f2fs/partclone_f2fs-mount.o: f2fs/mount.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_f2fs_CFLAGS) $(CFLAGS) -MT f2fs/partclone_f2fs-mount.o -MD -MP -MF f2fs/$(DEPDIR)/partclone_f2fs-mount.Tpo -c -o f2fs/partclone_f2fs-mount.o `test -f 'f2fs/mount.c' || echo '$(srcdir)/'`f2fs/mount.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) f2fs/$(DEPDIR)/partclone_f2fs-mount.Tpo f2fs/$(DEPDIR)/partclone_f2fs-mount.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='f2fs/mount.c' object='f2fs/partclone_f2fs-mount.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_f2fs_CFLAGS) $(CFLAGS) -c -o f2fs/partclone_f2fs-mount.o `test -f 'f2fs/mount.c' || echo '$(srcdir)/'`f2fs/mount.c f2fs/partclone_f2fs-mount.obj: f2fs/mount.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_f2fs_CFLAGS) $(CFLAGS) -MT f2fs/partclone_f2fs-mount.obj -MD -MP -MF f2fs/$(DEPDIR)/partclone_f2fs-mount.Tpo -c -o f2fs/partclone_f2fs-mount.obj `if test -f 'f2fs/mount.c'; then $(CYGPATH_W) 'f2fs/mount.c'; else $(CYGPATH_W) '$(srcdir)/f2fs/mount.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) f2fs/$(DEPDIR)/partclone_f2fs-mount.Tpo f2fs/$(DEPDIR)/partclone_f2fs-mount.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='f2fs/mount.c' object='f2fs/partclone_f2fs-mount.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_f2fs_CFLAGS) $(CFLAGS) -c -o f2fs/partclone_f2fs-mount.obj `if test -f 'f2fs/mount.c'; then $(CYGPATH_W) 'f2fs/mount.c'; else $(CYGPATH_W) '$(srcdir)/f2fs/mount.c'; fi` partclone_fat-main.o: main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_fat_CFLAGS) $(CFLAGS) -MT partclone_fat-main.o -MD -MP -MF $(DEPDIR)/partclone_fat-main.Tpo -c -o partclone_fat-main.o `test -f 'main.c' || echo '$(srcdir)/'`main.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_fat-main.Tpo $(DEPDIR)/partclone_fat-main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='main.c' object='partclone_fat-main.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_fat_CFLAGS) $(CFLAGS) -c -o partclone_fat-main.o `test -f 'main.c' || echo '$(srcdir)/'`main.c partclone_fat-main.obj: main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_fat_CFLAGS) $(CFLAGS) -MT partclone_fat-main.obj -MD -MP -MF $(DEPDIR)/partclone_fat-main.Tpo -c -o partclone_fat-main.obj `if test -f 'main.c'; then $(CYGPATH_W) 'main.c'; else $(CYGPATH_W) '$(srcdir)/main.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_fat-main.Tpo $(DEPDIR)/partclone_fat-main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='main.c' object='partclone_fat-main.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_fat_CFLAGS) $(CFLAGS) -c -o partclone_fat-main.obj `if test -f 'main.c'; then $(CYGPATH_W) 'main.c'; else $(CYGPATH_W) '$(srcdir)/main.c'; fi` partclone_fat-partclone.o: partclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_fat_CFLAGS) $(CFLAGS) -MT partclone_fat-partclone.o -MD -MP -MF $(DEPDIR)/partclone_fat-partclone.Tpo -c -o partclone_fat-partclone.o `test -f 'partclone.c' || echo '$(srcdir)/'`partclone.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_fat-partclone.Tpo $(DEPDIR)/partclone_fat-partclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='partclone.c' object='partclone_fat-partclone.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_fat_CFLAGS) $(CFLAGS) -c -o partclone_fat-partclone.o `test -f 'partclone.c' || echo '$(srcdir)/'`partclone.c partclone_fat-partclone.obj: partclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_fat_CFLAGS) $(CFLAGS) -MT partclone_fat-partclone.obj -MD -MP -MF $(DEPDIR)/partclone_fat-partclone.Tpo -c -o partclone_fat-partclone.obj `if test -f 'partclone.c'; then $(CYGPATH_W) 'partclone.c'; else $(CYGPATH_W) '$(srcdir)/partclone.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_fat-partclone.Tpo $(DEPDIR)/partclone_fat-partclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='partclone.c' object='partclone_fat-partclone.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_fat_CFLAGS) $(CFLAGS) -c -o partclone_fat-partclone.obj `if test -f 'partclone.c'; then $(CYGPATH_W) 'partclone.c'; else $(CYGPATH_W) '$(srcdir)/partclone.c'; fi` partclone_fat-progress.o: progress.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_fat_CFLAGS) $(CFLAGS) -MT partclone_fat-progress.o -MD -MP -MF $(DEPDIR)/partclone_fat-progress.Tpo -c -o partclone_fat-progress.o `test -f 'progress.c' || echo '$(srcdir)/'`progress.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_fat-progress.Tpo $(DEPDIR)/partclone_fat-progress.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='progress.c' object='partclone_fat-progress.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_fat_CFLAGS) $(CFLAGS) -c -o partclone_fat-progress.o `test -f 'progress.c' || echo '$(srcdir)/'`progress.c partclone_fat-progress.obj: progress.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_fat_CFLAGS) $(CFLAGS) -MT partclone_fat-progress.obj -MD -MP -MF $(DEPDIR)/partclone_fat-progress.Tpo -c -o partclone_fat-progress.obj `if test -f 'progress.c'; then $(CYGPATH_W) 'progress.c'; else $(CYGPATH_W) '$(srcdir)/progress.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_fat-progress.Tpo $(DEPDIR)/partclone_fat-progress.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='progress.c' object='partclone_fat-progress.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_fat_CFLAGS) $(CFLAGS) -c -o partclone_fat-progress.obj `if test -f 'progress.c'; then $(CYGPATH_W) 'progress.c'; else $(CYGPATH_W) '$(srcdir)/progress.c'; fi` partclone_fat-fatclone.o: fatclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_fat_CFLAGS) $(CFLAGS) -MT partclone_fat-fatclone.o -MD -MP -MF $(DEPDIR)/partclone_fat-fatclone.Tpo -c -o partclone_fat-fatclone.o `test -f 'fatclone.c' || echo '$(srcdir)/'`fatclone.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_fat-fatclone.Tpo $(DEPDIR)/partclone_fat-fatclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fatclone.c' object='partclone_fat-fatclone.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_fat_CFLAGS) $(CFLAGS) -c -o partclone_fat-fatclone.o `test -f 'fatclone.c' || echo '$(srcdir)/'`fatclone.c partclone_fat-fatclone.obj: fatclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_fat_CFLAGS) $(CFLAGS) -MT partclone_fat-fatclone.obj -MD -MP -MF $(DEPDIR)/partclone_fat-fatclone.Tpo -c -o partclone_fat-fatclone.obj `if test -f 'fatclone.c'; then $(CYGPATH_W) 'fatclone.c'; else $(CYGPATH_W) '$(srcdir)/fatclone.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_fat-fatclone.Tpo $(DEPDIR)/partclone_fat-fatclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fatclone.c' object='partclone_fat-fatclone.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_fat_CFLAGS) $(CFLAGS) -c -o partclone_fat-fatclone.obj `if test -f 'fatclone.c'; then $(CYGPATH_W) 'fatclone.c'; else $(CYGPATH_W) '$(srcdir)/fatclone.c'; fi` partclone_fstype-fstype.o: fstype.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_fstype_CFLAGS) $(CFLAGS) -MT partclone_fstype-fstype.o -MD -MP -MF $(DEPDIR)/partclone_fstype-fstype.Tpo -c -o partclone_fstype-fstype.o `test -f 'fstype.c' || echo '$(srcdir)/'`fstype.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_fstype-fstype.Tpo $(DEPDIR)/partclone_fstype-fstype.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fstype.c' object='partclone_fstype-fstype.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_fstype_CFLAGS) $(CFLAGS) -c -o partclone_fstype-fstype.o `test -f 'fstype.c' || echo '$(srcdir)/'`fstype.c partclone_fstype-fstype.obj: fstype.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_fstype_CFLAGS) $(CFLAGS) -MT partclone_fstype-fstype.obj -MD -MP -MF $(DEPDIR)/partclone_fstype-fstype.Tpo -c -o partclone_fstype-fstype.obj `if test -f 'fstype.c'; then $(CYGPATH_W) 'fstype.c'; else $(CYGPATH_W) '$(srcdir)/fstype.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_fstype-fstype.Tpo $(DEPDIR)/partclone_fstype-fstype.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fstype.c' object='partclone_fstype-fstype.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_fstype_CFLAGS) $(CFLAGS) -c -o partclone_fstype-fstype.obj `if test -f 'fstype.c'; then $(CYGPATH_W) 'fstype.c'; else $(CYGPATH_W) '$(srcdir)/fstype.c'; fi` partclone_hfsp-main.o: main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_hfsp_CFLAGS) $(CFLAGS) -MT partclone_hfsp-main.o -MD -MP -MF $(DEPDIR)/partclone_hfsp-main.Tpo -c -o partclone_hfsp-main.o `test -f 'main.c' || echo '$(srcdir)/'`main.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_hfsp-main.Tpo $(DEPDIR)/partclone_hfsp-main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='main.c' object='partclone_hfsp-main.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_hfsp_CFLAGS) $(CFLAGS) -c -o partclone_hfsp-main.o `test -f 'main.c' || echo '$(srcdir)/'`main.c partclone_hfsp-main.obj: main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_hfsp_CFLAGS) $(CFLAGS) -MT partclone_hfsp-main.obj -MD -MP -MF $(DEPDIR)/partclone_hfsp-main.Tpo -c -o partclone_hfsp-main.obj `if test -f 'main.c'; then $(CYGPATH_W) 'main.c'; else $(CYGPATH_W) '$(srcdir)/main.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_hfsp-main.Tpo $(DEPDIR)/partclone_hfsp-main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='main.c' object='partclone_hfsp-main.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_hfsp_CFLAGS) $(CFLAGS) -c -o partclone_hfsp-main.obj `if test -f 'main.c'; then $(CYGPATH_W) 'main.c'; else $(CYGPATH_W) '$(srcdir)/main.c'; fi` partclone_hfsp-partclone.o: partclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_hfsp_CFLAGS) $(CFLAGS) -MT partclone_hfsp-partclone.o -MD -MP -MF $(DEPDIR)/partclone_hfsp-partclone.Tpo -c -o partclone_hfsp-partclone.o `test -f 'partclone.c' || echo '$(srcdir)/'`partclone.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_hfsp-partclone.Tpo $(DEPDIR)/partclone_hfsp-partclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='partclone.c' object='partclone_hfsp-partclone.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_hfsp_CFLAGS) $(CFLAGS) -c -o partclone_hfsp-partclone.o `test -f 'partclone.c' || echo '$(srcdir)/'`partclone.c partclone_hfsp-partclone.obj: partclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_hfsp_CFLAGS) $(CFLAGS) -MT partclone_hfsp-partclone.obj -MD -MP -MF $(DEPDIR)/partclone_hfsp-partclone.Tpo -c -o partclone_hfsp-partclone.obj `if test -f 'partclone.c'; then $(CYGPATH_W) 'partclone.c'; else $(CYGPATH_W) '$(srcdir)/partclone.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_hfsp-partclone.Tpo $(DEPDIR)/partclone_hfsp-partclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='partclone.c' object='partclone_hfsp-partclone.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_hfsp_CFLAGS) $(CFLAGS) -c -o partclone_hfsp-partclone.obj `if test -f 'partclone.c'; then $(CYGPATH_W) 'partclone.c'; else $(CYGPATH_W) '$(srcdir)/partclone.c'; fi` partclone_hfsp-progress.o: progress.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_hfsp_CFLAGS) $(CFLAGS) -MT partclone_hfsp-progress.o -MD -MP -MF $(DEPDIR)/partclone_hfsp-progress.Tpo -c -o partclone_hfsp-progress.o `test -f 'progress.c' || echo '$(srcdir)/'`progress.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_hfsp-progress.Tpo $(DEPDIR)/partclone_hfsp-progress.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='progress.c' object='partclone_hfsp-progress.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_hfsp_CFLAGS) $(CFLAGS) -c -o partclone_hfsp-progress.o `test -f 'progress.c' || echo '$(srcdir)/'`progress.c partclone_hfsp-progress.obj: progress.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_hfsp_CFLAGS) $(CFLAGS) -MT partclone_hfsp-progress.obj -MD -MP -MF $(DEPDIR)/partclone_hfsp-progress.Tpo -c -o partclone_hfsp-progress.obj `if test -f 'progress.c'; then $(CYGPATH_W) 'progress.c'; else $(CYGPATH_W) '$(srcdir)/progress.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_hfsp-progress.Tpo $(DEPDIR)/partclone_hfsp-progress.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='progress.c' object='partclone_hfsp-progress.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_hfsp_CFLAGS) $(CFLAGS) -c -o partclone_hfsp-progress.obj `if test -f 'progress.c'; then $(CYGPATH_W) 'progress.c'; else $(CYGPATH_W) '$(srcdir)/progress.c'; fi` partclone_hfsp-hfsplusclone.o: hfsplusclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_hfsp_CFLAGS) $(CFLAGS) -MT partclone_hfsp-hfsplusclone.o -MD -MP -MF $(DEPDIR)/partclone_hfsp-hfsplusclone.Tpo -c -o partclone_hfsp-hfsplusclone.o `test -f 'hfsplusclone.c' || echo '$(srcdir)/'`hfsplusclone.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_hfsp-hfsplusclone.Tpo $(DEPDIR)/partclone_hfsp-hfsplusclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='hfsplusclone.c' object='partclone_hfsp-hfsplusclone.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_hfsp_CFLAGS) $(CFLAGS) -c -o partclone_hfsp-hfsplusclone.o `test -f 'hfsplusclone.c' || echo '$(srcdir)/'`hfsplusclone.c partclone_hfsp-hfsplusclone.obj: hfsplusclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_hfsp_CFLAGS) $(CFLAGS) -MT partclone_hfsp-hfsplusclone.obj -MD -MP -MF $(DEPDIR)/partclone_hfsp-hfsplusclone.Tpo -c -o partclone_hfsp-hfsplusclone.obj `if test -f 'hfsplusclone.c'; then $(CYGPATH_W) 'hfsplusclone.c'; else $(CYGPATH_W) '$(srcdir)/hfsplusclone.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_hfsp-hfsplusclone.Tpo $(DEPDIR)/partclone_hfsp-hfsplusclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='hfsplusclone.c' object='partclone_hfsp-hfsplusclone.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_hfsp_CFLAGS) $(CFLAGS) -c -o partclone_hfsp-hfsplusclone.obj `if test -f 'hfsplusclone.c'; then $(CYGPATH_W) 'hfsplusclone.c'; else $(CYGPATH_W) '$(srcdir)/hfsplusclone.c'; fi` partclone_imager-main.o: main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_imager_CFLAGS) $(CFLAGS) -MT partclone_imager-main.o -MD -MP -MF $(DEPDIR)/partclone_imager-main.Tpo -c -o partclone_imager-main.o `test -f 'main.c' || echo '$(srcdir)/'`main.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_imager-main.Tpo $(DEPDIR)/partclone_imager-main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='main.c' object='partclone_imager-main.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_imager_CFLAGS) $(CFLAGS) -c -o partclone_imager-main.o `test -f 'main.c' || echo '$(srcdir)/'`main.c partclone_imager-main.obj: main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_imager_CFLAGS) $(CFLAGS) -MT partclone_imager-main.obj -MD -MP -MF $(DEPDIR)/partclone_imager-main.Tpo -c -o partclone_imager-main.obj `if test -f 'main.c'; then $(CYGPATH_W) 'main.c'; else $(CYGPATH_W) '$(srcdir)/main.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_imager-main.Tpo $(DEPDIR)/partclone_imager-main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='main.c' object='partclone_imager-main.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_imager_CFLAGS) $(CFLAGS) -c -o partclone_imager-main.obj `if test -f 'main.c'; then $(CYGPATH_W) 'main.c'; else $(CYGPATH_W) '$(srcdir)/main.c'; fi` partclone_imager-partclone.o: partclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_imager_CFLAGS) $(CFLAGS) -MT partclone_imager-partclone.o -MD -MP -MF $(DEPDIR)/partclone_imager-partclone.Tpo -c -o partclone_imager-partclone.o `test -f 'partclone.c' || echo '$(srcdir)/'`partclone.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_imager-partclone.Tpo $(DEPDIR)/partclone_imager-partclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='partclone.c' object='partclone_imager-partclone.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_imager_CFLAGS) $(CFLAGS) -c -o partclone_imager-partclone.o `test -f 'partclone.c' || echo '$(srcdir)/'`partclone.c partclone_imager-partclone.obj: partclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_imager_CFLAGS) $(CFLAGS) -MT partclone_imager-partclone.obj -MD -MP -MF $(DEPDIR)/partclone_imager-partclone.Tpo -c -o partclone_imager-partclone.obj `if test -f 'partclone.c'; then $(CYGPATH_W) 'partclone.c'; else $(CYGPATH_W) '$(srcdir)/partclone.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_imager-partclone.Tpo $(DEPDIR)/partclone_imager-partclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='partclone.c' object='partclone_imager-partclone.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_imager_CFLAGS) $(CFLAGS) -c -o partclone_imager-partclone.obj `if test -f 'partclone.c'; then $(CYGPATH_W) 'partclone.c'; else $(CYGPATH_W) '$(srcdir)/partclone.c'; fi` partclone_imager-progress.o: progress.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_imager_CFLAGS) $(CFLAGS) -MT partclone_imager-progress.o -MD -MP -MF $(DEPDIR)/partclone_imager-progress.Tpo -c -o partclone_imager-progress.o `test -f 'progress.c' || echo '$(srcdir)/'`progress.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_imager-progress.Tpo $(DEPDIR)/partclone_imager-progress.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='progress.c' object='partclone_imager-progress.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_imager_CFLAGS) $(CFLAGS) -c -o partclone_imager-progress.o `test -f 'progress.c' || echo '$(srcdir)/'`progress.c partclone_imager-progress.obj: progress.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_imager_CFLAGS) $(CFLAGS) -MT partclone_imager-progress.obj -MD -MP -MF $(DEPDIR)/partclone_imager-progress.Tpo -c -o partclone_imager-progress.obj `if test -f 'progress.c'; then $(CYGPATH_W) 'progress.c'; else $(CYGPATH_W) '$(srcdir)/progress.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_imager-progress.Tpo $(DEPDIR)/partclone_imager-progress.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='progress.c' object='partclone_imager-progress.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_imager_CFLAGS) $(CFLAGS) -c -o partclone_imager-progress.obj `if test -f 'progress.c'; then $(CYGPATH_W) 'progress.c'; else $(CYGPATH_W) '$(srcdir)/progress.c'; fi` partclone_imager-ddclone.o: ddclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_imager_CFLAGS) $(CFLAGS) -MT partclone_imager-ddclone.o -MD -MP -MF $(DEPDIR)/partclone_imager-ddclone.Tpo -c -o partclone_imager-ddclone.o `test -f 'ddclone.c' || echo '$(srcdir)/'`ddclone.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_imager-ddclone.Tpo $(DEPDIR)/partclone_imager-ddclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ddclone.c' object='partclone_imager-ddclone.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_imager_CFLAGS) $(CFLAGS) -c -o partclone_imager-ddclone.o `test -f 'ddclone.c' || echo '$(srcdir)/'`ddclone.c partclone_imager-ddclone.obj: ddclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_imager_CFLAGS) $(CFLAGS) -MT partclone_imager-ddclone.obj -MD -MP -MF $(DEPDIR)/partclone_imager-ddclone.Tpo -c -o partclone_imager-ddclone.obj `if test -f 'ddclone.c'; then $(CYGPATH_W) 'ddclone.c'; else $(CYGPATH_W) '$(srcdir)/ddclone.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_imager-ddclone.Tpo $(DEPDIR)/partclone_imager-ddclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ddclone.c' object='partclone_imager-ddclone.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_imager_CFLAGS) $(CFLAGS) -c -o partclone_imager-ddclone.obj `if test -f 'ddclone.c'; then $(CYGPATH_W) 'ddclone.c'; else $(CYGPATH_W) '$(srcdir)/ddclone.c'; fi` partclone_jfs-main.o: main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_jfs_CFLAGS) $(CFLAGS) -MT partclone_jfs-main.o -MD -MP -MF $(DEPDIR)/partclone_jfs-main.Tpo -c -o partclone_jfs-main.o `test -f 'main.c' || echo '$(srcdir)/'`main.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_jfs-main.Tpo $(DEPDIR)/partclone_jfs-main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='main.c' object='partclone_jfs-main.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_jfs_CFLAGS) $(CFLAGS) -c -o partclone_jfs-main.o `test -f 'main.c' || echo '$(srcdir)/'`main.c partclone_jfs-main.obj: main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_jfs_CFLAGS) $(CFLAGS) -MT partclone_jfs-main.obj -MD -MP -MF $(DEPDIR)/partclone_jfs-main.Tpo -c -o partclone_jfs-main.obj `if test -f 'main.c'; then $(CYGPATH_W) 'main.c'; else $(CYGPATH_W) '$(srcdir)/main.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_jfs-main.Tpo $(DEPDIR)/partclone_jfs-main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='main.c' object='partclone_jfs-main.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_jfs_CFLAGS) $(CFLAGS) -c -o partclone_jfs-main.obj `if test -f 'main.c'; then $(CYGPATH_W) 'main.c'; else $(CYGPATH_W) '$(srcdir)/main.c'; fi` partclone_jfs-partclone.o: partclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_jfs_CFLAGS) $(CFLAGS) -MT partclone_jfs-partclone.o -MD -MP -MF $(DEPDIR)/partclone_jfs-partclone.Tpo -c -o partclone_jfs-partclone.o `test -f 'partclone.c' || echo '$(srcdir)/'`partclone.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_jfs-partclone.Tpo $(DEPDIR)/partclone_jfs-partclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='partclone.c' object='partclone_jfs-partclone.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_jfs_CFLAGS) $(CFLAGS) -c -o partclone_jfs-partclone.o `test -f 'partclone.c' || echo '$(srcdir)/'`partclone.c partclone_jfs-partclone.obj: partclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_jfs_CFLAGS) $(CFLAGS) -MT partclone_jfs-partclone.obj -MD -MP -MF $(DEPDIR)/partclone_jfs-partclone.Tpo -c -o partclone_jfs-partclone.obj `if test -f 'partclone.c'; then $(CYGPATH_W) 'partclone.c'; else $(CYGPATH_W) '$(srcdir)/partclone.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_jfs-partclone.Tpo $(DEPDIR)/partclone_jfs-partclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='partclone.c' object='partclone_jfs-partclone.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_jfs_CFLAGS) $(CFLAGS) -c -o partclone_jfs-partclone.obj `if test -f 'partclone.c'; then $(CYGPATH_W) 'partclone.c'; else $(CYGPATH_W) '$(srcdir)/partclone.c'; fi` partclone_jfs-progress.o: progress.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_jfs_CFLAGS) $(CFLAGS) -MT partclone_jfs-progress.o -MD -MP -MF $(DEPDIR)/partclone_jfs-progress.Tpo -c -o partclone_jfs-progress.o `test -f 'progress.c' || echo '$(srcdir)/'`progress.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_jfs-progress.Tpo $(DEPDIR)/partclone_jfs-progress.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='progress.c' object='partclone_jfs-progress.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_jfs_CFLAGS) $(CFLAGS) -c -o partclone_jfs-progress.o `test -f 'progress.c' || echo '$(srcdir)/'`progress.c partclone_jfs-progress.obj: progress.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_jfs_CFLAGS) $(CFLAGS) -MT partclone_jfs-progress.obj -MD -MP -MF $(DEPDIR)/partclone_jfs-progress.Tpo -c -o partclone_jfs-progress.obj `if test -f 'progress.c'; then $(CYGPATH_W) 'progress.c'; else $(CYGPATH_W) '$(srcdir)/progress.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_jfs-progress.Tpo $(DEPDIR)/partclone_jfs-progress.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='progress.c' object='partclone_jfs-progress.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_jfs_CFLAGS) $(CFLAGS) -c -o partclone_jfs-progress.obj `if test -f 'progress.c'; then $(CYGPATH_W) 'progress.c'; else $(CYGPATH_W) '$(srcdir)/progress.c'; fi` partclone_jfs-jfsclone.o: jfsclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_jfs_CFLAGS) $(CFLAGS) -MT partclone_jfs-jfsclone.o -MD -MP -MF $(DEPDIR)/partclone_jfs-jfsclone.Tpo -c -o partclone_jfs-jfsclone.o `test -f 'jfsclone.c' || echo '$(srcdir)/'`jfsclone.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_jfs-jfsclone.Tpo $(DEPDIR)/partclone_jfs-jfsclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='jfsclone.c' object='partclone_jfs-jfsclone.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_jfs_CFLAGS) $(CFLAGS) -c -o partclone_jfs-jfsclone.o `test -f 'jfsclone.c' || echo '$(srcdir)/'`jfsclone.c partclone_jfs-jfsclone.obj: jfsclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_jfs_CFLAGS) $(CFLAGS) -MT partclone_jfs-jfsclone.obj -MD -MP -MF $(DEPDIR)/partclone_jfs-jfsclone.Tpo -c -o partclone_jfs-jfsclone.obj `if test -f 'jfsclone.c'; then $(CYGPATH_W) 'jfsclone.c'; else $(CYGPATH_W) '$(srcdir)/jfsclone.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_jfs-jfsclone.Tpo $(DEPDIR)/partclone_jfs-jfsclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='jfsclone.c' object='partclone_jfs-jfsclone.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_jfs_CFLAGS) $(CFLAGS) -c -o partclone_jfs-jfsclone.obj `if test -f 'jfsclone.c'; then $(CYGPATH_W) 'jfsclone.c'; else $(CYGPATH_W) '$(srcdir)/jfsclone.c'; fi` partclone_minix-main.o: main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_minix_CFLAGS) $(CFLAGS) -MT partclone_minix-main.o -MD -MP -MF $(DEPDIR)/partclone_minix-main.Tpo -c -o partclone_minix-main.o `test -f 'main.c' || echo '$(srcdir)/'`main.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_minix-main.Tpo $(DEPDIR)/partclone_minix-main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='main.c' object='partclone_minix-main.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_minix_CFLAGS) $(CFLAGS) -c -o partclone_minix-main.o `test -f 'main.c' || echo '$(srcdir)/'`main.c partclone_minix-main.obj: main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_minix_CFLAGS) $(CFLAGS) -MT partclone_minix-main.obj -MD -MP -MF $(DEPDIR)/partclone_minix-main.Tpo -c -o partclone_minix-main.obj `if test -f 'main.c'; then $(CYGPATH_W) 'main.c'; else $(CYGPATH_W) '$(srcdir)/main.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_minix-main.Tpo $(DEPDIR)/partclone_minix-main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='main.c' object='partclone_minix-main.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_minix_CFLAGS) $(CFLAGS) -c -o partclone_minix-main.obj `if test -f 'main.c'; then $(CYGPATH_W) 'main.c'; else $(CYGPATH_W) '$(srcdir)/main.c'; fi` partclone_minix-partclone.o: partclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_minix_CFLAGS) $(CFLAGS) -MT partclone_minix-partclone.o -MD -MP -MF $(DEPDIR)/partclone_minix-partclone.Tpo -c -o partclone_minix-partclone.o `test -f 'partclone.c' || echo '$(srcdir)/'`partclone.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_minix-partclone.Tpo $(DEPDIR)/partclone_minix-partclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='partclone.c' object='partclone_minix-partclone.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_minix_CFLAGS) $(CFLAGS) -c -o partclone_minix-partclone.o `test -f 'partclone.c' || echo '$(srcdir)/'`partclone.c partclone_minix-partclone.obj: partclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_minix_CFLAGS) $(CFLAGS) -MT partclone_minix-partclone.obj -MD -MP -MF $(DEPDIR)/partclone_minix-partclone.Tpo -c -o partclone_minix-partclone.obj `if test -f 'partclone.c'; then $(CYGPATH_W) 'partclone.c'; else $(CYGPATH_W) '$(srcdir)/partclone.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_minix-partclone.Tpo $(DEPDIR)/partclone_minix-partclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='partclone.c' object='partclone_minix-partclone.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_minix_CFLAGS) $(CFLAGS) -c -o partclone_minix-partclone.obj `if test -f 'partclone.c'; then $(CYGPATH_W) 'partclone.c'; else $(CYGPATH_W) '$(srcdir)/partclone.c'; fi` partclone_minix-progress.o: progress.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_minix_CFLAGS) $(CFLAGS) -MT partclone_minix-progress.o -MD -MP -MF $(DEPDIR)/partclone_minix-progress.Tpo -c -o partclone_minix-progress.o `test -f 'progress.c' || echo '$(srcdir)/'`progress.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_minix-progress.Tpo $(DEPDIR)/partclone_minix-progress.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='progress.c' object='partclone_minix-progress.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_minix_CFLAGS) $(CFLAGS) -c -o partclone_minix-progress.o `test -f 'progress.c' || echo '$(srcdir)/'`progress.c partclone_minix-progress.obj: progress.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_minix_CFLAGS) $(CFLAGS) -MT partclone_minix-progress.obj -MD -MP -MF $(DEPDIR)/partclone_minix-progress.Tpo -c -o partclone_minix-progress.obj `if test -f 'progress.c'; then $(CYGPATH_W) 'progress.c'; else $(CYGPATH_W) '$(srcdir)/progress.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_minix-progress.Tpo $(DEPDIR)/partclone_minix-progress.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='progress.c' object='partclone_minix-progress.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_minix_CFLAGS) $(CFLAGS) -c -o partclone_minix-progress.obj `if test -f 'progress.c'; then $(CYGPATH_W) 'progress.c'; else $(CYGPATH_W) '$(srcdir)/progress.c'; fi` partclone_minix-minixclone.o: minixclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_minix_CFLAGS) $(CFLAGS) -MT partclone_minix-minixclone.o -MD -MP -MF $(DEPDIR)/partclone_minix-minixclone.Tpo -c -o partclone_minix-minixclone.o `test -f 'minixclone.c' || echo '$(srcdir)/'`minixclone.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_minix-minixclone.Tpo $(DEPDIR)/partclone_minix-minixclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='minixclone.c' object='partclone_minix-minixclone.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_minix_CFLAGS) $(CFLAGS) -c -o partclone_minix-minixclone.o `test -f 'minixclone.c' || echo '$(srcdir)/'`minixclone.c partclone_minix-minixclone.obj: minixclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_minix_CFLAGS) $(CFLAGS) -MT partclone_minix-minixclone.obj -MD -MP -MF $(DEPDIR)/partclone_minix-minixclone.Tpo -c -o partclone_minix-minixclone.obj `if test -f 'minixclone.c'; then $(CYGPATH_W) 'minixclone.c'; else $(CYGPATH_W) '$(srcdir)/minixclone.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_minix-minixclone.Tpo $(DEPDIR)/partclone_minix-minixclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='minixclone.c' object='partclone_minix-minixclone.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_minix_CFLAGS) $(CFLAGS) -c -o partclone_minix-minixclone.obj `if test -f 'minixclone.c'; then $(CYGPATH_W) 'minixclone.c'; else $(CYGPATH_W) '$(srcdir)/minixclone.c'; fi` partclone_nilfs2-main.o: main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_nilfs2_CFLAGS) $(CFLAGS) -MT partclone_nilfs2-main.o -MD -MP -MF $(DEPDIR)/partclone_nilfs2-main.Tpo -c -o partclone_nilfs2-main.o `test -f 'main.c' || echo '$(srcdir)/'`main.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_nilfs2-main.Tpo $(DEPDIR)/partclone_nilfs2-main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='main.c' object='partclone_nilfs2-main.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_nilfs2_CFLAGS) $(CFLAGS) -c -o partclone_nilfs2-main.o `test -f 'main.c' || echo '$(srcdir)/'`main.c partclone_nilfs2-main.obj: main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_nilfs2_CFLAGS) $(CFLAGS) -MT partclone_nilfs2-main.obj -MD -MP -MF $(DEPDIR)/partclone_nilfs2-main.Tpo -c -o partclone_nilfs2-main.obj `if test -f 'main.c'; then $(CYGPATH_W) 'main.c'; else $(CYGPATH_W) '$(srcdir)/main.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_nilfs2-main.Tpo $(DEPDIR)/partclone_nilfs2-main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='main.c' object='partclone_nilfs2-main.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_nilfs2_CFLAGS) $(CFLAGS) -c -o partclone_nilfs2-main.obj `if test -f 'main.c'; then $(CYGPATH_W) 'main.c'; else $(CYGPATH_W) '$(srcdir)/main.c'; fi` partclone_nilfs2-partclone.o: partclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_nilfs2_CFLAGS) $(CFLAGS) -MT partclone_nilfs2-partclone.o -MD -MP -MF $(DEPDIR)/partclone_nilfs2-partclone.Tpo -c -o partclone_nilfs2-partclone.o `test -f 'partclone.c' || echo '$(srcdir)/'`partclone.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_nilfs2-partclone.Tpo $(DEPDIR)/partclone_nilfs2-partclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='partclone.c' object='partclone_nilfs2-partclone.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_nilfs2_CFLAGS) $(CFLAGS) -c -o partclone_nilfs2-partclone.o `test -f 'partclone.c' || echo '$(srcdir)/'`partclone.c partclone_nilfs2-partclone.obj: partclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_nilfs2_CFLAGS) $(CFLAGS) -MT partclone_nilfs2-partclone.obj -MD -MP -MF $(DEPDIR)/partclone_nilfs2-partclone.Tpo -c -o partclone_nilfs2-partclone.obj `if test -f 'partclone.c'; then $(CYGPATH_W) 'partclone.c'; else $(CYGPATH_W) '$(srcdir)/partclone.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_nilfs2-partclone.Tpo $(DEPDIR)/partclone_nilfs2-partclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='partclone.c' object='partclone_nilfs2-partclone.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_nilfs2_CFLAGS) $(CFLAGS) -c -o partclone_nilfs2-partclone.obj `if test -f 'partclone.c'; then $(CYGPATH_W) 'partclone.c'; else $(CYGPATH_W) '$(srcdir)/partclone.c'; fi` partclone_nilfs2-progress.o: progress.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_nilfs2_CFLAGS) $(CFLAGS) -MT partclone_nilfs2-progress.o -MD -MP -MF $(DEPDIR)/partclone_nilfs2-progress.Tpo -c -o partclone_nilfs2-progress.o `test -f 'progress.c' || echo '$(srcdir)/'`progress.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_nilfs2-progress.Tpo $(DEPDIR)/partclone_nilfs2-progress.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='progress.c' object='partclone_nilfs2-progress.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_nilfs2_CFLAGS) $(CFLAGS) -c -o partclone_nilfs2-progress.o `test -f 'progress.c' || echo '$(srcdir)/'`progress.c partclone_nilfs2-progress.obj: progress.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_nilfs2_CFLAGS) $(CFLAGS) -MT partclone_nilfs2-progress.obj -MD -MP -MF $(DEPDIR)/partclone_nilfs2-progress.Tpo -c -o partclone_nilfs2-progress.obj `if test -f 'progress.c'; then $(CYGPATH_W) 'progress.c'; else $(CYGPATH_W) '$(srcdir)/progress.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_nilfs2-progress.Tpo $(DEPDIR)/partclone_nilfs2-progress.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='progress.c' object='partclone_nilfs2-progress.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_nilfs2_CFLAGS) $(CFLAGS) -c -o partclone_nilfs2-progress.obj `if test -f 'progress.c'; then $(CYGPATH_W) 'progress.c'; else $(CYGPATH_W) '$(srcdir)/progress.c'; fi` partclone_nilfs2-nilfsclone.o: nilfsclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_nilfs2_CFLAGS) $(CFLAGS) -MT partclone_nilfs2-nilfsclone.o -MD -MP -MF $(DEPDIR)/partclone_nilfs2-nilfsclone.Tpo -c -o partclone_nilfs2-nilfsclone.o `test -f 'nilfsclone.c' || echo '$(srcdir)/'`nilfsclone.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_nilfs2-nilfsclone.Tpo $(DEPDIR)/partclone_nilfs2-nilfsclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nilfsclone.c' object='partclone_nilfs2-nilfsclone.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_nilfs2_CFLAGS) $(CFLAGS) -c -o partclone_nilfs2-nilfsclone.o `test -f 'nilfsclone.c' || echo '$(srcdir)/'`nilfsclone.c partclone_nilfs2-nilfsclone.obj: nilfsclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_nilfs2_CFLAGS) $(CFLAGS) -MT partclone_nilfs2-nilfsclone.obj -MD -MP -MF $(DEPDIR)/partclone_nilfs2-nilfsclone.Tpo -c -o partclone_nilfs2-nilfsclone.obj `if test -f 'nilfsclone.c'; then $(CYGPATH_W) 'nilfsclone.c'; else $(CYGPATH_W) '$(srcdir)/nilfsclone.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_nilfs2-nilfsclone.Tpo $(DEPDIR)/partclone_nilfs2-nilfsclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nilfsclone.c' object='partclone_nilfs2-nilfsclone.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_nilfs2_CFLAGS) $(CFLAGS) -c -o partclone_nilfs2-nilfsclone.obj `if test -f 'nilfsclone.c'; then $(CYGPATH_W) 'nilfsclone.c'; else $(CYGPATH_W) '$(srcdir)/nilfsclone.c'; fi` partclone_ntfs-main.o: main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_ntfs_CFLAGS) $(CFLAGS) -MT partclone_ntfs-main.o -MD -MP -MF $(DEPDIR)/partclone_ntfs-main.Tpo -c -o partclone_ntfs-main.o `test -f 'main.c' || echo '$(srcdir)/'`main.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_ntfs-main.Tpo $(DEPDIR)/partclone_ntfs-main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='main.c' object='partclone_ntfs-main.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_ntfs_CFLAGS) $(CFLAGS) -c -o partclone_ntfs-main.o `test -f 'main.c' || echo '$(srcdir)/'`main.c partclone_ntfs-main.obj: main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_ntfs_CFLAGS) $(CFLAGS) -MT partclone_ntfs-main.obj -MD -MP -MF $(DEPDIR)/partclone_ntfs-main.Tpo -c -o partclone_ntfs-main.obj `if test -f 'main.c'; then $(CYGPATH_W) 'main.c'; else $(CYGPATH_W) '$(srcdir)/main.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_ntfs-main.Tpo $(DEPDIR)/partclone_ntfs-main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='main.c' object='partclone_ntfs-main.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_ntfs_CFLAGS) $(CFLAGS) -c -o partclone_ntfs-main.obj `if test -f 'main.c'; then $(CYGPATH_W) 'main.c'; else $(CYGPATH_W) '$(srcdir)/main.c'; fi` partclone_ntfs-partclone.o: partclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_ntfs_CFLAGS) $(CFLAGS) -MT partclone_ntfs-partclone.o -MD -MP -MF $(DEPDIR)/partclone_ntfs-partclone.Tpo -c -o partclone_ntfs-partclone.o `test -f 'partclone.c' || echo '$(srcdir)/'`partclone.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_ntfs-partclone.Tpo $(DEPDIR)/partclone_ntfs-partclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='partclone.c' object='partclone_ntfs-partclone.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_ntfs_CFLAGS) $(CFLAGS) -c -o partclone_ntfs-partclone.o `test -f 'partclone.c' || echo '$(srcdir)/'`partclone.c partclone_ntfs-partclone.obj: partclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_ntfs_CFLAGS) $(CFLAGS) -MT partclone_ntfs-partclone.obj -MD -MP -MF $(DEPDIR)/partclone_ntfs-partclone.Tpo -c -o partclone_ntfs-partclone.obj `if test -f 'partclone.c'; then $(CYGPATH_W) 'partclone.c'; else $(CYGPATH_W) '$(srcdir)/partclone.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_ntfs-partclone.Tpo $(DEPDIR)/partclone_ntfs-partclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='partclone.c' object='partclone_ntfs-partclone.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_ntfs_CFLAGS) $(CFLAGS) -c -o partclone_ntfs-partclone.obj `if test -f 'partclone.c'; then $(CYGPATH_W) 'partclone.c'; else $(CYGPATH_W) '$(srcdir)/partclone.c'; fi` partclone_ntfs-progress.o: progress.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_ntfs_CFLAGS) $(CFLAGS) -MT partclone_ntfs-progress.o -MD -MP -MF $(DEPDIR)/partclone_ntfs-progress.Tpo -c -o partclone_ntfs-progress.o `test -f 'progress.c' || echo '$(srcdir)/'`progress.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_ntfs-progress.Tpo $(DEPDIR)/partclone_ntfs-progress.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='progress.c' object='partclone_ntfs-progress.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_ntfs_CFLAGS) $(CFLAGS) -c -o partclone_ntfs-progress.o `test -f 'progress.c' || echo '$(srcdir)/'`progress.c partclone_ntfs-progress.obj: progress.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_ntfs_CFLAGS) $(CFLAGS) -MT partclone_ntfs-progress.obj -MD -MP -MF $(DEPDIR)/partclone_ntfs-progress.Tpo -c -o partclone_ntfs-progress.obj `if test -f 'progress.c'; then $(CYGPATH_W) 'progress.c'; else $(CYGPATH_W) '$(srcdir)/progress.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_ntfs-progress.Tpo $(DEPDIR)/partclone_ntfs-progress.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='progress.c' object='partclone_ntfs-progress.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_ntfs_CFLAGS) $(CFLAGS) -c -o partclone_ntfs-progress.obj `if test -f 'progress.c'; then $(CYGPATH_W) 'progress.c'; else $(CYGPATH_W) '$(srcdir)/progress.c'; fi` partclone_ntfs-ntfsclone-ng.o: ntfsclone-ng.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_ntfs_CFLAGS) $(CFLAGS) -MT partclone_ntfs-ntfsclone-ng.o -MD -MP -MF $(DEPDIR)/partclone_ntfs-ntfsclone-ng.Tpo -c -o partclone_ntfs-ntfsclone-ng.o `test -f 'ntfsclone-ng.c' || echo '$(srcdir)/'`ntfsclone-ng.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_ntfs-ntfsclone-ng.Tpo $(DEPDIR)/partclone_ntfs-ntfsclone-ng.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ntfsclone-ng.c' object='partclone_ntfs-ntfsclone-ng.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_ntfs_CFLAGS) $(CFLAGS) -c -o partclone_ntfs-ntfsclone-ng.o `test -f 'ntfsclone-ng.c' || echo '$(srcdir)/'`ntfsclone-ng.c partclone_ntfs-ntfsclone-ng.obj: ntfsclone-ng.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_ntfs_CFLAGS) $(CFLAGS) -MT partclone_ntfs-ntfsclone-ng.obj -MD -MP -MF $(DEPDIR)/partclone_ntfs-ntfsclone-ng.Tpo -c -o partclone_ntfs-ntfsclone-ng.obj `if test -f 'ntfsclone-ng.c'; then $(CYGPATH_W) 'ntfsclone-ng.c'; else $(CYGPATH_W) '$(srcdir)/ntfsclone-ng.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_ntfs-ntfsclone-ng.Tpo $(DEPDIR)/partclone_ntfs-ntfsclone-ng.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ntfsclone-ng.c' object='partclone_ntfs-ntfsclone-ng.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_ntfs_CFLAGS) $(CFLAGS) -c -o partclone_ntfs-ntfsclone-ng.obj `if test -f 'ntfsclone-ng.c'; then $(CYGPATH_W) 'ntfsclone-ng.c'; else $(CYGPATH_W) '$(srcdir)/ntfsclone-ng.c'; fi` partclone_reiser4-main.o: main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_reiser4_CFLAGS) $(CFLAGS) -MT partclone_reiser4-main.o -MD -MP -MF $(DEPDIR)/partclone_reiser4-main.Tpo -c -o partclone_reiser4-main.o `test -f 'main.c' || echo '$(srcdir)/'`main.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_reiser4-main.Tpo $(DEPDIR)/partclone_reiser4-main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='main.c' object='partclone_reiser4-main.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_reiser4_CFLAGS) $(CFLAGS) -c -o partclone_reiser4-main.o `test -f 'main.c' || echo '$(srcdir)/'`main.c partclone_reiser4-main.obj: main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_reiser4_CFLAGS) $(CFLAGS) -MT partclone_reiser4-main.obj -MD -MP -MF $(DEPDIR)/partclone_reiser4-main.Tpo -c -o partclone_reiser4-main.obj `if test -f 'main.c'; then $(CYGPATH_W) 'main.c'; else $(CYGPATH_W) '$(srcdir)/main.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_reiser4-main.Tpo $(DEPDIR)/partclone_reiser4-main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='main.c' object='partclone_reiser4-main.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_reiser4_CFLAGS) $(CFLAGS) -c -o partclone_reiser4-main.obj `if test -f 'main.c'; then $(CYGPATH_W) 'main.c'; else $(CYGPATH_W) '$(srcdir)/main.c'; fi` partclone_reiser4-partclone.o: partclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_reiser4_CFLAGS) $(CFLAGS) -MT partclone_reiser4-partclone.o -MD -MP -MF $(DEPDIR)/partclone_reiser4-partclone.Tpo -c -o partclone_reiser4-partclone.o `test -f 'partclone.c' || echo '$(srcdir)/'`partclone.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_reiser4-partclone.Tpo $(DEPDIR)/partclone_reiser4-partclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='partclone.c' object='partclone_reiser4-partclone.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_reiser4_CFLAGS) $(CFLAGS) -c -o partclone_reiser4-partclone.o `test -f 'partclone.c' || echo '$(srcdir)/'`partclone.c partclone_reiser4-partclone.obj: partclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_reiser4_CFLAGS) $(CFLAGS) -MT partclone_reiser4-partclone.obj -MD -MP -MF $(DEPDIR)/partclone_reiser4-partclone.Tpo -c -o partclone_reiser4-partclone.obj `if test -f 'partclone.c'; then $(CYGPATH_W) 'partclone.c'; else $(CYGPATH_W) '$(srcdir)/partclone.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_reiser4-partclone.Tpo $(DEPDIR)/partclone_reiser4-partclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='partclone.c' object='partclone_reiser4-partclone.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_reiser4_CFLAGS) $(CFLAGS) -c -o partclone_reiser4-partclone.obj `if test -f 'partclone.c'; then $(CYGPATH_W) 'partclone.c'; else $(CYGPATH_W) '$(srcdir)/partclone.c'; fi` partclone_reiser4-progress.o: progress.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_reiser4_CFLAGS) $(CFLAGS) -MT partclone_reiser4-progress.o -MD -MP -MF $(DEPDIR)/partclone_reiser4-progress.Tpo -c -o partclone_reiser4-progress.o `test -f 'progress.c' || echo '$(srcdir)/'`progress.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_reiser4-progress.Tpo $(DEPDIR)/partclone_reiser4-progress.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='progress.c' object='partclone_reiser4-progress.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_reiser4_CFLAGS) $(CFLAGS) -c -o partclone_reiser4-progress.o `test -f 'progress.c' || echo '$(srcdir)/'`progress.c partclone_reiser4-progress.obj: progress.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_reiser4_CFLAGS) $(CFLAGS) -MT partclone_reiser4-progress.obj -MD -MP -MF $(DEPDIR)/partclone_reiser4-progress.Tpo -c -o partclone_reiser4-progress.obj `if test -f 'progress.c'; then $(CYGPATH_W) 'progress.c'; else $(CYGPATH_W) '$(srcdir)/progress.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_reiser4-progress.Tpo $(DEPDIR)/partclone_reiser4-progress.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='progress.c' object='partclone_reiser4-progress.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_reiser4_CFLAGS) $(CFLAGS) -c -o partclone_reiser4-progress.obj `if test -f 'progress.c'; then $(CYGPATH_W) 'progress.c'; else $(CYGPATH_W) '$(srcdir)/progress.c'; fi` partclone_reiser4-reiser4clone.o: reiser4clone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_reiser4_CFLAGS) $(CFLAGS) -MT partclone_reiser4-reiser4clone.o -MD -MP -MF $(DEPDIR)/partclone_reiser4-reiser4clone.Tpo -c -o partclone_reiser4-reiser4clone.o `test -f 'reiser4clone.c' || echo '$(srcdir)/'`reiser4clone.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_reiser4-reiser4clone.Tpo $(DEPDIR)/partclone_reiser4-reiser4clone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='reiser4clone.c' object='partclone_reiser4-reiser4clone.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_reiser4_CFLAGS) $(CFLAGS) -c -o partclone_reiser4-reiser4clone.o `test -f 'reiser4clone.c' || echo '$(srcdir)/'`reiser4clone.c partclone_reiser4-reiser4clone.obj: reiser4clone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_reiser4_CFLAGS) $(CFLAGS) -MT partclone_reiser4-reiser4clone.obj -MD -MP -MF $(DEPDIR)/partclone_reiser4-reiser4clone.Tpo -c -o partclone_reiser4-reiser4clone.obj `if test -f 'reiser4clone.c'; then $(CYGPATH_W) 'reiser4clone.c'; else $(CYGPATH_W) '$(srcdir)/reiser4clone.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_reiser4-reiser4clone.Tpo $(DEPDIR)/partclone_reiser4-reiser4clone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='reiser4clone.c' object='partclone_reiser4-reiser4clone.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_reiser4_CFLAGS) $(CFLAGS) -c -o partclone_reiser4-reiser4clone.obj `if test -f 'reiser4clone.c'; then $(CYGPATH_W) 'reiser4clone.c'; else $(CYGPATH_W) '$(srcdir)/reiser4clone.c'; fi` partclone_reiserfs-main.o: main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_reiserfs_CFLAGS) $(CFLAGS) -MT partclone_reiserfs-main.o -MD -MP -MF $(DEPDIR)/partclone_reiserfs-main.Tpo -c -o partclone_reiserfs-main.o `test -f 'main.c' || echo '$(srcdir)/'`main.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_reiserfs-main.Tpo $(DEPDIR)/partclone_reiserfs-main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='main.c' object='partclone_reiserfs-main.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_reiserfs_CFLAGS) $(CFLAGS) -c -o partclone_reiserfs-main.o `test -f 'main.c' || echo '$(srcdir)/'`main.c partclone_reiserfs-main.obj: main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_reiserfs_CFLAGS) $(CFLAGS) -MT partclone_reiserfs-main.obj -MD -MP -MF $(DEPDIR)/partclone_reiserfs-main.Tpo -c -o partclone_reiserfs-main.obj `if test -f 'main.c'; then $(CYGPATH_W) 'main.c'; else $(CYGPATH_W) '$(srcdir)/main.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_reiserfs-main.Tpo $(DEPDIR)/partclone_reiserfs-main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='main.c' object='partclone_reiserfs-main.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_reiserfs_CFLAGS) $(CFLAGS) -c -o partclone_reiserfs-main.obj `if test -f 'main.c'; then $(CYGPATH_W) 'main.c'; else $(CYGPATH_W) '$(srcdir)/main.c'; fi` partclone_reiserfs-partclone.o: partclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_reiserfs_CFLAGS) $(CFLAGS) -MT partclone_reiserfs-partclone.o -MD -MP -MF $(DEPDIR)/partclone_reiserfs-partclone.Tpo -c -o partclone_reiserfs-partclone.o `test -f 'partclone.c' || echo '$(srcdir)/'`partclone.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_reiserfs-partclone.Tpo $(DEPDIR)/partclone_reiserfs-partclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='partclone.c' object='partclone_reiserfs-partclone.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_reiserfs_CFLAGS) $(CFLAGS) -c -o partclone_reiserfs-partclone.o `test -f 'partclone.c' || echo '$(srcdir)/'`partclone.c partclone_reiserfs-partclone.obj: partclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_reiserfs_CFLAGS) $(CFLAGS) -MT partclone_reiserfs-partclone.obj -MD -MP -MF $(DEPDIR)/partclone_reiserfs-partclone.Tpo -c -o partclone_reiserfs-partclone.obj `if test -f 'partclone.c'; then $(CYGPATH_W) 'partclone.c'; else $(CYGPATH_W) '$(srcdir)/partclone.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_reiserfs-partclone.Tpo $(DEPDIR)/partclone_reiserfs-partclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='partclone.c' object='partclone_reiserfs-partclone.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_reiserfs_CFLAGS) $(CFLAGS) -c -o partclone_reiserfs-partclone.obj `if test -f 'partclone.c'; then $(CYGPATH_W) 'partclone.c'; else $(CYGPATH_W) '$(srcdir)/partclone.c'; fi` partclone_reiserfs-progress.o: progress.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_reiserfs_CFLAGS) $(CFLAGS) -MT partclone_reiserfs-progress.o -MD -MP -MF $(DEPDIR)/partclone_reiserfs-progress.Tpo -c -o partclone_reiserfs-progress.o `test -f 'progress.c' || echo '$(srcdir)/'`progress.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_reiserfs-progress.Tpo $(DEPDIR)/partclone_reiserfs-progress.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='progress.c' object='partclone_reiserfs-progress.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_reiserfs_CFLAGS) $(CFLAGS) -c -o partclone_reiserfs-progress.o `test -f 'progress.c' || echo '$(srcdir)/'`progress.c partclone_reiserfs-progress.obj: progress.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_reiserfs_CFLAGS) $(CFLAGS) -MT partclone_reiserfs-progress.obj -MD -MP -MF $(DEPDIR)/partclone_reiserfs-progress.Tpo -c -o partclone_reiserfs-progress.obj `if test -f 'progress.c'; then $(CYGPATH_W) 'progress.c'; else $(CYGPATH_W) '$(srcdir)/progress.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_reiserfs-progress.Tpo $(DEPDIR)/partclone_reiserfs-progress.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='progress.c' object='partclone_reiserfs-progress.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_reiserfs_CFLAGS) $(CFLAGS) -c -o partclone_reiserfs-progress.obj `if test -f 'progress.c'; then $(CYGPATH_W) 'progress.c'; else $(CYGPATH_W) '$(srcdir)/progress.c'; fi` partclone_reiserfs-reiserfsclone.o: reiserfsclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_reiserfs_CFLAGS) $(CFLAGS) -MT partclone_reiserfs-reiserfsclone.o -MD -MP -MF $(DEPDIR)/partclone_reiserfs-reiserfsclone.Tpo -c -o partclone_reiserfs-reiserfsclone.o `test -f 'reiserfsclone.c' || echo '$(srcdir)/'`reiserfsclone.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_reiserfs-reiserfsclone.Tpo $(DEPDIR)/partclone_reiserfs-reiserfsclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='reiserfsclone.c' object='partclone_reiserfs-reiserfsclone.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_reiserfs_CFLAGS) $(CFLAGS) -c -o partclone_reiserfs-reiserfsclone.o `test -f 'reiserfsclone.c' || echo '$(srcdir)/'`reiserfsclone.c partclone_reiserfs-reiserfsclone.obj: reiserfsclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_reiserfs_CFLAGS) $(CFLAGS) -MT partclone_reiserfs-reiserfsclone.obj -MD -MP -MF $(DEPDIR)/partclone_reiserfs-reiserfsclone.Tpo -c -o partclone_reiserfs-reiserfsclone.obj `if test -f 'reiserfsclone.c'; then $(CYGPATH_W) 'reiserfsclone.c'; else $(CYGPATH_W) '$(srcdir)/reiserfsclone.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_reiserfs-reiserfsclone.Tpo $(DEPDIR)/partclone_reiserfs-reiserfsclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='reiserfsclone.c' object='partclone_reiserfs-reiserfsclone.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_reiserfs_CFLAGS) $(CFLAGS) -c -o partclone_reiserfs-reiserfsclone.obj `if test -f 'reiserfsclone.c'; then $(CYGPATH_W) 'reiserfsclone.c'; else $(CYGPATH_W) '$(srcdir)/reiserfsclone.c'; fi` partclone_restore-main.o: main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_restore_CFLAGS) $(CFLAGS) -MT partclone_restore-main.o -MD -MP -MF $(DEPDIR)/partclone_restore-main.Tpo -c -o partclone_restore-main.o `test -f 'main.c' || echo '$(srcdir)/'`main.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_restore-main.Tpo $(DEPDIR)/partclone_restore-main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='main.c' object='partclone_restore-main.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_restore_CFLAGS) $(CFLAGS) -c -o partclone_restore-main.o `test -f 'main.c' || echo '$(srcdir)/'`main.c partclone_restore-main.obj: main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_restore_CFLAGS) $(CFLAGS) -MT partclone_restore-main.obj -MD -MP -MF $(DEPDIR)/partclone_restore-main.Tpo -c -o partclone_restore-main.obj `if test -f 'main.c'; then $(CYGPATH_W) 'main.c'; else $(CYGPATH_W) '$(srcdir)/main.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_restore-main.Tpo $(DEPDIR)/partclone_restore-main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='main.c' object='partclone_restore-main.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_restore_CFLAGS) $(CFLAGS) -c -o partclone_restore-main.obj `if test -f 'main.c'; then $(CYGPATH_W) 'main.c'; else $(CYGPATH_W) '$(srcdir)/main.c'; fi` partclone_restore-partclone.o: partclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_restore_CFLAGS) $(CFLAGS) -MT partclone_restore-partclone.o -MD -MP -MF $(DEPDIR)/partclone_restore-partclone.Tpo -c -o partclone_restore-partclone.o `test -f 'partclone.c' || echo '$(srcdir)/'`partclone.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_restore-partclone.Tpo $(DEPDIR)/partclone_restore-partclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='partclone.c' object='partclone_restore-partclone.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_restore_CFLAGS) $(CFLAGS) -c -o partclone_restore-partclone.o `test -f 'partclone.c' || echo '$(srcdir)/'`partclone.c partclone_restore-partclone.obj: partclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_restore_CFLAGS) $(CFLAGS) -MT partclone_restore-partclone.obj -MD -MP -MF $(DEPDIR)/partclone_restore-partclone.Tpo -c -o partclone_restore-partclone.obj `if test -f 'partclone.c'; then $(CYGPATH_W) 'partclone.c'; else $(CYGPATH_W) '$(srcdir)/partclone.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_restore-partclone.Tpo $(DEPDIR)/partclone_restore-partclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='partclone.c' object='partclone_restore-partclone.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_restore_CFLAGS) $(CFLAGS) -c -o partclone_restore-partclone.obj `if test -f 'partclone.c'; then $(CYGPATH_W) 'partclone.c'; else $(CYGPATH_W) '$(srcdir)/partclone.c'; fi` partclone_restore-progress.o: progress.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_restore_CFLAGS) $(CFLAGS) -MT partclone_restore-progress.o -MD -MP -MF $(DEPDIR)/partclone_restore-progress.Tpo -c -o partclone_restore-progress.o `test -f 'progress.c' || echo '$(srcdir)/'`progress.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_restore-progress.Tpo $(DEPDIR)/partclone_restore-progress.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='progress.c' object='partclone_restore-progress.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_restore_CFLAGS) $(CFLAGS) -c -o partclone_restore-progress.o `test -f 'progress.c' || echo '$(srcdir)/'`progress.c partclone_restore-progress.obj: progress.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_restore_CFLAGS) $(CFLAGS) -MT partclone_restore-progress.obj -MD -MP -MF $(DEPDIR)/partclone_restore-progress.Tpo -c -o partclone_restore-progress.obj `if test -f 'progress.c'; then $(CYGPATH_W) 'progress.c'; else $(CYGPATH_W) '$(srcdir)/progress.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_restore-progress.Tpo $(DEPDIR)/partclone_restore-progress.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='progress.c' object='partclone_restore-progress.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_restore_CFLAGS) $(CFLAGS) -c -o partclone_restore-progress.obj `if test -f 'progress.c'; then $(CYGPATH_W) 'progress.c'; else $(CYGPATH_W) '$(srcdir)/progress.c'; fi` partclone_restore-ddclone.o: ddclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_restore_CFLAGS) $(CFLAGS) -MT partclone_restore-ddclone.o -MD -MP -MF $(DEPDIR)/partclone_restore-ddclone.Tpo -c -o partclone_restore-ddclone.o `test -f 'ddclone.c' || echo '$(srcdir)/'`ddclone.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_restore-ddclone.Tpo $(DEPDIR)/partclone_restore-ddclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ddclone.c' object='partclone_restore-ddclone.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_restore_CFLAGS) $(CFLAGS) -c -o partclone_restore-ddclone.o `test -f 'ddclone.c' || echo '$(srcdir)/'`ddclone.c partclone_restore-ddclone.obj: ddclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_restore_CFLAGS) $(CFLAGS) -MT partclone_restore-ddclone.obj -MD -MP -MF $(DEPDIR)/partclone_restore-ddclone.Tpo -c -o partclone_restore-ddclone.obj `if test -f 'ddclone.c'; then $(CYGPATH_W) 'ddclone.c'; else $(CYGPATH_W) '$(srcdir)/ddclone.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_restore-ddclone.Tpo $(DEPDIR)/partclone_restore-ddclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ddclone.c' object='partclone_restore-ddclone.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_restore_CFLAGS) $(CFLAGS) -c -o partclone_restore-ddclone.obj `if test -f 'ddclone.c'; then $(CYGPATH_W) 'ddclone.c'; else $(CYGPATH_W) '$(srcdir)/ddclone.c'; fi` partclone_ufs-main.o: main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_ufs_CFLAGS) $(CFLAGS) -MT partclone_ufs-main.o -MD -MP -MF $(DEPDIR)/partclone_ufs-main.Tpo -c -o partclone_ufs-main.o `test -f 'main.c' || echo '$(srcdir)/'`main.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_ufs-main.Tpo $(DEPDIR)/partclone_ufs-main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='main.c' object='partclone_ufs-main.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_ufs_CFLAGS) $(CFLAGS) -c -o partclone_ufs-main.o `test -f 'main.c' || echo '$(srcdir)/'`main.c partclone_ufs-main.obj: main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_ufs_CFLAGS) $(CFLAGS) -MT partclone_ufs-main.obj -MD -MP -MF $(DEPDIR)/partclone_ufs-main.Tpo -c -o partclone_ufs-main.obj `if test -f 'main.c'; then $(CYGPATH_W) 'main.c'; else $(CYGPATH_W) '$(srcdir)/main.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_ufs-main.Tpo $(DEPDIR)/partclone_ufs-main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='main.c' object='partclone_ufs-main.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_ufs_CFLAGS) $(CFLAGS) -c -o partclone_ufs-main.obj `if test -f 'main.c'; then $(CYGPATH_W) 'main.c'; else $(CYGPATH_W) '$(srcdir)/main.c'; fi` partclone_ufs-partclone.o: partclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_ufs_CFLAGS) $(CFLAGS) -MT partclone_ufs-partclone.o -MD -MP -MF $(DEPDIR)/partclone_ufs-partclone.Tpo -c -o partclone_ufs-partclone.o `test -f 'partclone.c' || echo '$(srcdir)/'`partclone.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_ufs-partclone.Tpo $(DEPDIR)/partclone_ufs-partclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='partclone.c' object='partclone_ufs-partclone.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_ufs_CFLAGS) $(CFLAGS) -c -o partclone_ufs-partclone.o `test -f 'partclone.c' || echo '$(srcdir)/'`partclone.c partclone_ufs-partclone.obj: partclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_ufs_CFLAGS) $(CFLAGS) -MT partclone_ufs-partclone.obj -MD -MP -MF $(DEPDIR)/partclone_ufs-partclone.Tpo -c -o partclone_ufs-partclone.obj `if test -f 'partclone.c'; then $(CYGPATH_W) 'partclone.c'; else $(CYGPATH_W) '$(srcdir)/partclone.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_ufs-partclone.Tpo $(DEPDIR)/partclone_ufs-partclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='partclone.c' object='partclone_ufs-partclone.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_ufs_CFLAGS) $(CFLAGS) -c -o partclone_ufs-partclone.obj `if test -f 'partclone.c'; then $(CYGPATH_W) 'partclone.c'; else $(CYGPATH_W) '$(srcdir)/partclone.c'; fi` partclone_ufs-progress.o: progress.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_ufs_CFLAGS) $(CFLAGS) -MT partclone_ufs-progress.o -MD -MP -MF $(DEPDIR)/partclone_ufs-progress.Tpo -c -o partclone_ufs-progress.o `test -f 'progress.c' || echo '$(srcdir)/'`progress.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_ufs-progress.Tpo $(DEPDIR)/partclone_ufs-progress.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='progress.c' object='partclone_ufs-progress.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_ufs_CFLAGS) $(CFLAGS) -c -o partclone_ufs-progress.o `test -f 'progress.c' || echo '$(srcdir)/'`progress.c partclone_ufs-progress.obj: progress.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_ufs_CFLAGS) $(CFLAGS) -MT partclone_ufs-progress.obj -MD -MP -MF $(DEPDIR)/partclone_ufs-progress.Tpo -c -o partclone_ufs-progress.obj `if test -f 'progress.c'; then $(CYGPATH_W) 'progress.c'; else $(CYGPATH_W) '$(srcdir)/progress.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_ufs-progress.Tpo $(DEPDIR)/partclone_ufs-progress.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='progress.c' object='partclone_ufs-progress.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_ufs_CFLAGS) $(CFLAGS) -c -o partclone_ufs-progress.obj `if test -f 'progress.c'; then $(CYGPATH_W) 'progress.c'; else $(CYGPATH_W) '$(srcdir)/progress.c'; fi` partclone_ufs-ufsclone.o: ufsclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_ufs_CFLAGS) $(CFLAGS) -MT partclone_ufs-ufsclone.o -MD -MP -MF $(DEPDIR)/partclone_ufs-ufsclone.Tpo -c -o partclone_ufs-ufsclone.o `test -f 'ufsclone.c' || echo '$(srcdir)/'`ufsclone.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_ufs-ufsclone.Tpo $(DEPDIR)/partclone_ufs-ufsclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ufsclone.c' object='partclone_ufs-ufsclone.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_ufs_CFLAGS) $(CFLAGS) -c -o partclone_ufs-ufsclone.o `test -f 'ufsclone.c' || echo '$(srcdir)/'`ufsclone.c partclone_ufs-ufsclone.obj: ufsclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_ufs_CFLAGS) $(CFLAGS) -MT partclone_ufs-ufsclone.obj -MD -MP -MF $(DEPDIR)/partclone_ufs-ufsclone.Tpo -c -o partclone_ufs-ufsclone.obj `if test -f 'ufsclone.c'; then $(CYGPATH_W) 'ufsclone.c'; else $(CYGPATH_W) '$(srcdir)/ufsclone.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_ufs-ufsclone.Tpo $(DEPDIR)/partclone_ufs-ufsclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ufsclone.c' object='partclone_ufs-ufsclone.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_ufs_CFLAGS) $(CFLAGS) -c -o partclone_ufs-ufsclone.obj `if test -f 'ufsclone.c'; then $(CYGPATH_W) 'ufsclone.c'; else $(CYGPATH_W) '$(srcdir)/ufsclone.c'; fi` partclone_vmfs-main.o: main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_vmfs_CFLAGS) $(CFLAGS) -MT partclone_vmfs-main.o -MD -MP -MF $(DEPDIR)/partclone_vmfs-main.Tpo -c -o partclone_vmfs-main.o `test -f 'main.c' || echo '$(srcdir)/'`main.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_vmfs-main.Tpo $(DEPDIR)/partclone_vmfs-main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='main.c' object='partclone_vmfs-main.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_vmfs_CFLAGS) $(CFLAGS) -c -o partclone_vmfs-main.o `test -f 'main.c' || echo '$(srcdir)/'`main.c partclone_vmfs-main.obj: main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_vmfs_CFLAGS) $(CFLAGS) -MT partclone_vmfs-main.obj -MD -MP -MF $(DEPDIR)/partclone_vmfs-main.Tpo -c -o partclone_vmfs-main.obj `if test -f 'main.c'; then $(CYGPATH_W) 'main.c'; else $(CYGPATH_W) '$(srcdir)/main.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_vmfs-main.Tpo $(DEPDIR)/partclone_vmfs-main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='main.c' object='partclone_vmfs-main.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_vmfs_CFLAGS) $(CFLAGS) -c -o partclone_vmfs-main.obj `if test -f 'main.c'; then $(CYGPATH_W) 'main.c'; else $(CYGPATH_W) '$(srcdir)/main.c'; fi` partclone_vmfs-partclone.o: partclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_vmfs_CFLAGS) $(CFLAGS) -MT partclone_vmfs-partclone.o -MD -MP -MF $(DEPDIR)/partclone_vmfs-partclone.Tpo -c -o partclone_vmfs-partclone.o `test -f 'partclone.c' || echo '$(srcdir)/'`partclone.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_vmfs-partclone.Tpo $(DEPDIR)/partclone_vmfs-partclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='partclone.c' object='partclone_vmfs-partclone.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_vmfs_CFLAGS) $(CFLAGS) -c -o partclone_vmfs-partclone.o `test -f 'partclone.c' || echo '$(srcdir)/'`partclone.c partclone_vmfs-partclone.obj: partclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_vmfs_CFLAGS) $(CFLAGS) -MT partclone_vmfs-partclone.obj -MD -MP -MF $(DEPDIR)/partclone_vmfs-partclone.Tpo -c -o partclone_vmfs-partclone.obj `if test -f 'partclone.c'; then $(CYGPATH_W) 'partclone.c'; else $(CYGPATH_W) '$(srcdir)/partclone.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_vmfs-partclone.Tpo $(DEPDIR)/partclone_vmfs-partclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='partclone.c' object='partclone_vmfs-partclone.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_vmfs_CFLAGS) $(CFLAGS) -c -o partclone_vmfs-partclone.obj `if test -f 'partclone.c'; then $(CYGPATH_W) 'partclone.c'; else $(CYGPATH_W) '$(srcdir)/partclone.c'; fi` partclone_vmfs-progress.o: progress.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_vmfs_CFLAGS) $(CFLAGS) -MT partclone_vmfs-progress.o -MD -MP -MF $(DEPDIR)/partclone_vmfs-progress.Tpo -c -o partclone_vmfs-progress.o `test -f 'progress.c' || echo '$(srcdir)/'`progress.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_vmfs-progress.Tpo $(DEPDIR)/partclone_vmfs-progress.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='progress.c' object='partclone_vmfs-progress.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_vmfs_CFLAGS) $(CFLAGS) -c -o partclone_vmfs-progress.o `test -f 'progress.c' || echo '$(srcdir)/'`progress.c partclone_vmfs-progress.obj: progress.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_vmfs_CFLAGS) $(CFLAGS) -MT partclone_vmfs-progress.obj -MD -MP -MF $(DEPDIR)/partclone_vmfs-progress.Tpo -c -o partclone_vmfs-progress.obj `if test -f 'progress.c'; then $(CYGPATH_W) 'progress.c'; else $(CYGPATH_W) '$(srcdir)/progress.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_vmfs-progress.Tpo $(DEPDIR)/partclone_vmfs-progress.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='progress.c' object='partclone_vmfs-progress.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_vmfs_CFLAGS) $(CFLAGS) -c -o partclone_vmfs-progress.obj `if test -f 'progress.c'; then $(CYGPATH_W) 'progress.c'; else $(CYGPATH_W) '$(srcdir)/progress.c'; fi` partclone_vmfs-vmfsclone.o: vmfsclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_vmfs_CFLAGS) $(CFLAGS) -MT partclone_vmfs-vmfsclone.o -MD -MP -MF $(DEPDIR)/partclone_vmfs-vmfsclone.Tpo -c -o partclone_vmfs-vmfsclone.o `test -f 'vmfsclone.c' || echo '$(srcdir)/'`vmfsclone.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_vmfs-vmfsclone.Tpo $(DEPDIR)/partclone_vmfs-vmfsclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vmfsclone.c' object='partclone_vmfs-vmfsclone.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_vmfs_CFLAGS) $(CFLAGS) -c -o partclone_vmfs-vmfsclone.o `test -f 'vmfsclone.c' || echo '$(srcdir)/'`vmfsclone.c partclone_vmfs-vmfsclone.obj: vmfsclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_vmfs_CFLAGS) $(CFLAGS) -MT partclone_vmfs-vmfsclone.obj -MD -MP -MF $(DEPDIR)/partclone_vmfs-vmfsclone.Tpo -c -o partclone_vmfs-vmfsclone.obj `if test -f 'vmfsclone.c'; then $(CYGPATH_W) 'vmfsclone.c'; else $(CYGPATH_W) '$(srcdir)/vmfsclone.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_vmfs-vmfsclone.Tpo $(DEPDIR)/partclone_vmfs-vmfsclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vmfsclone.c' object='partclone_vmfs-vmfsclone.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_vmfs_CFLAGS) $(CFLAGS) -c -o partclone_vmfs-vmfsclone.obj `if test -f 'vmfsclone.c'; then $(CYGPATH_W) 'vmfsclone.c'; else $(CYGPATH_W) '$(srcdir)/vmfsclone.c'; fi` partclone_vmfs5-main.o: main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_vmfs5_CFLAGS) $(CFLAGS) -MT partclone_vmfs5-main.o -MD -MP -MF $(DEPDIR)/partclone_vmfs5-main.Tpo -c -o partclone_vmfs5-main.o `test -f 'main.c' || echo '$(srcdir)/'`main.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_vmfs5-main.Tpo $(DEPDIR)/partclone_vmfs5-main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='main.c' object='partclone_vmfs5-main.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_vmfs5_CFLAGS) $(CFLAGS) -c -o partclone_vmfs5-main.o `test -f 'main.c' || echo '$(srcdir)/'`main.c partclone_vmfs5-main.obj: main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_vmfs5_CFLAGS) $(CFLAGS) -MT partclone_vmfs5-main.obj -MD -MP -MF $(DEPDIR)/partclone_vmfs5-main.Tpo -c -o partclone_vmfs5-main.obj `if test -f 'main.c'; then $(CYGPATH_W) 'main.c'; else $(CYGPATH_W) '$(srcdir)/main.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_vmfs5-main.Tpo $(DEPDIR)/partclone_vmfs5-main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='main.c' object='partclone_vmfs5-main.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_vmfs5_CFLAGS) $(CFLAGS) -c -o partclone_vmfs5-main.obj `if test -f 'main.c'; then $(CYGPATH_W) 'main.c'; else $(CYGPATH_W) '$(srcdir)/main.c'; fi` partclone_vmfs5-partclone.o: partclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_vmfs5_CFLAGS) $(CFLAGS) -MT partclone_vmfs5-partclone.o -MD -MP -MF $(DEPDIR)/partclone_vmfs5-partclone.Tpo -c -o partclone_vmfs5-partclone.o `test -f 'partclone.c' || echo '$(srcdir)/'`partclone.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_vmfs5-partclone.Tpo $(DEPDIR)/partclone_vmfs5-partclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='partclone.c' object='partclone_vmfs5-partclone.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_vmfs5_CFLAGS) $(CFLAGS) -c -o partclone_vmfs5-partclone.o `test -f 'partclone.c' || echo '$(srcdir)/'`partclone.c partclone_vmfs5-partclone.obj: partclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_vmfs5_CFLAGS) $(CFLAGS) -MT partclone_vmfs5-partclone.obj -MD -MP -MF $(DEPDIR)/partclone_vmfs5-partclone.Tpo -c -o partclone_vmfs5-partclone.obj `if test -f 'partclone.c'; then $(CYGPATH_W) 'partclone.c'; else $(CYGPATH_W) '$(srcdir)/partclone.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_vmfs5-partclone.Tpo $(DEPDIR)/partclone_vmfs5-partclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='partclone.c' object='partclone_vmfs5-partclone.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_vmfs5_CFLAGS) $(CFLAGS) -c -o partclone_vmfs5-partclone.obj `if test -f 'partclone.c'; then $(CYGPATH_W) 'partclone.c'; else $(CYGPATH_W) '$(srcdir)/partclone.c'; fi` partclone_vmfs5-progress.o: progress.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_vmfs5_CFLAGS) $(CFLAGS) -MT partclone_vmfs5-progress.o -MD -MP -MF $(DEPDIR)/partclone_vmfs5-progress.Tpo -c -o partclone_vmfs5-progress.o `test -f 'progress.c' || echo '$(srcdir)/'`progress.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_vmfs5-progress.Tpo $(DEPDIR)/partclone_vmfs5-progress.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='progress.c' object='partclone_vmfs5-progress.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_vmfs5_CFLAGS) $(CFLAGS) -c -o partclone_vmfs5-progress.o `test -f 'progress.c' || echo '$(srcdir)/'`progress.c partclone_vmfs5-progress.obj: progress.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_vmfs5_CFLAGS) $(CFLAGS) -MT partclone_vmfs5-progress.obj -MD -MP -MF $(DEPDIR)/partclone_vmfs5-progress.Tpo -c -o partclone_vmfs5-progress.obj `if test -f 'progress.c'; then $(CYGPATH_W) 'progress.c'; else $(CYGPATH_W) '$(srcdir)/progress.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_vmfs5-progress.Tpo $(DEPDIR)/partclone_vmfs5-progress.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='progress.c' object='partclone_vmfs5-progress.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_vmfs5_CFLAGS) $(CFLAGS) -c -o partclone_vmfs5-progress.obj `if test -f 'progress.c'; then $(CYGPATH_W) 'progress.c'; else $(CYGPATH_W) '$(srcdir)/progress.c'; fi` partclone_vmfs5-vmfs5clone.o: vmfs5clone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_vmfs5_CFLAGS) $(CFLAGS) -MT partclone_vmfs5-vmfs5clone.o -MD -MP -MF $(DEPDIR)/partclone_vmfs5-vmfs5clone.Tpo -c -o partclone_vmfs5-vmfs5clone.o `test -f 'vmfs5clone.c' || echo '$(srcdir)/'`vmfs5clone.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_vmfs5-vmfs5clone.Tpo $(DEPDIR)/partclone_vmfs5-vmfs5clone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vmfs5clone.c' object='partclone_vmfs5-vmfs5clone.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_vmfs5_CFLAGS) $(CFLAGS) -c -o partclone_vmfs5-vmfs5clone.o `test -f 'vmfs5clone.c' || echo '$(srcdir)/'`vmfs5clone.c partclone_vmfs5-vmfs5clone.obj: vmfs5clone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_vmfs5_CFLAGS) $(CFLAGS) -MT partclone_vmfs5-vmfs5clone.obj -MD -MP -MF $(DEPDIR)/partclone_vmfs5-vmfs5clone.Tpo -c -o partclone_vmfs5-vmfs5clone.obj `if test -f 'vmfs5clone.c'; then $(CYGPATH_W) 'vmfs5clone.c'; else $(CYGPATH_W) '$(srcdir)/vmfs5clone.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_vmfs5-vmfs5clone.Tpo $(DEPDIR)/partclone_vmfs5-vmfs5clone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vmfs5clone.c' object='partclone_vmfs5-vmfs5clone.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_vmfs5_CFLAGS) $(CFLAGS) -c -o partclone_vmfs5-vmfs5clone.obj `if test -f 'vmfs5clone.c'; then $(CYGPATH_W) 'vmfs5clone.c'; else $(CYGPATH_W) '$(srcdir)/vmfs5clone.c'; fi` partclone_xfs-main.o: main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT partclone_xfs-main.o -MD -MP -MF $(DEPDIR)/partclone_xfs-main.Tpo -c -o partclone_xfs-main.o `test -f 'main.c' || echo '$(srcdir)/'`main.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_xfs-main.Tpo $(DEPDIR)/partclone_xfs-main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='main.c' object='partclone_xfs-main.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o partclone_xfs-main.o `test -f 'main.c' || echo '$(srcdir)/'`main.c partclone_xfs-main.obj: main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT partclone_xfs-main.obj -MD -MP -MF $(DEPDIR)/partclone_xfs-main.Tpo -c -o partclone_xfs-main.obj `if test -f 'main.c'; then $(CYGPATH_W) 'main.c'; else $(CYGPATH_W) '$(srcdir)/main.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_xfs-main.Tpo $(DEPDIR)/partclone_xfs-main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='main.c' object='partclone_xfs-main.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o partclone_xfs-main.obj `if test -f 'main.c'; then $(CYGPATH_W) 'main.c'; else $(CYGPATH_W) '$(srcdir)/main.c'; fi` partclone_xfs-partclone.o: partclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT partclone_xfs-partclone.o -MD -MP -MF $(DEPDIR)/partclone_xfs-partclone.Tpo -c -o partclone_xfs-partclone.o `test -f 'partclone.c' || echo '$(srcdir)/'`partclone.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_xfs-partclone.Tpo $(DEPDIR)/partclone_xfs-partclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='partclone.c' object='partclone_xfs-partclone.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o partclone_xfs-partclone.o `test -f 'partclone.c' || echo '$(srcdir)/'`partclone.c partclone_xfs-partclone.obj: partclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT partclone_xfs-partclone.obj -MD -MP -MF $(DEPDIR)/partclone_xfs-partclone.Tpo -c -o partclone_xfs-partclone.obj `if test -f 'partclone.c'; then $(CYGPATH_W) 'partclone.c'; else $(CYGPATH_W) '$(srcdir)/partclone.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_xfs-partclone.Tpo $(DEPDIR)/partclone_xfs-partclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='partclone.c' object='partclone_xfs-partclone.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o partclone_xfs-partclone.obj `if test -f 'partclone.c'; then $(CYGPATH_W) 'partclone.c'; else $(CYGPATH_W) '$(srcdir)/partclone.c'; fi` partclone_xfs-progress.o: progress.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT partclone_xfs-progress.o -MD -MP -MF $(DEPDIR)/partclone_xfs-progress.Tpo -c -o partclone_xfs-progress.o `test -f 'progress.c' || echo '$(srcdir)/'`progress.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_xfs-progress.Tpo $(DEPDIR)/partclone_xfs-progress.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='progress.c' object='partclone_xfs-progress.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o partclone_xfs-progress.o `test -f 'progress.c' || echo '$(srcdir)/'`progress.c partclone_xfs-progress.obj: progress.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT partclone_xfs-progress.obj -MD -MP -MF $(DEPDIR)/partclone_xfs-progress.Tpo -c -o partclone_xfs-progress.obj `if test -f 'progress.c'; then $(CYGPATH_W) 'progress.c'; else $(CYGPATH_W) '$(srcdir)/progress.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_xfs-progress.Tpo $(DEPDIR)/partclone_xfs-progress.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='progress.c' object='partclone_xfs-progress.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o partclone_xfs-progress.obj `if test -f 'progress.c'; then $(CYGPATH_W) 'progress.c'; else $(CYGPATH_W) '$(srcdir)/progress.c'; fi` partclone_xfs-xfsclone.o: xfsclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT partclone_xfs-xfsclone.o -MD -MP -MF $(DEPDIR)/partclone_xfs-xfsclone.Tpo -c -o partclone_xfs-xfsclone.o `test -f 'xfsclone.c' || echo '$(srcdir)/'`xfsclone.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_xfs-xfsclone.Tpo $(DEPDIR)/partclone_xfs-xfsclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfsclone.c' object='partclone_xfs-xfsclone.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o partclone_xfs-xfsclone.o `test -f 'xfsclone.c' || echo '$(srcdir)/'`xfsclone.c partclone_xfs-xfsclone.obj: xfsclone.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT partclone_xfs-xfsclone.obj -MD -MP -MF $(DEPDIR)/partclone_xfs-xfsclone.Tpo -c -o partclone_xfs-xfsclone.obj `if test -f 'xfsclone.c'; then $(CYGPATH_W) 'xfsclone.c'; else $(CYGPATH_W) '$(srcdir)/xfsclone.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/partclone_xfs-xfsclone.Tpo $(DEPDIR)/partclone_xfs-xfsclone.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfsclone.c' object='partclone_xfs-xfsclone.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o partclone_xfs-xfsclone.obj `if test -f 'xfsclone.c'; then $(CYGPATH_W) 'xfsclone.c'; else $(CYGPATH_W) '$(srcdir)/xfsclone.c'; fi` xfs/partclone_xfs-xfs_attr.o: xfs/xfs_attr.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-xfs_attr.o -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-xfs_attr.Tpo -c -o xfs/partclone_xfs-xfs_attr.o `test -f 'xfs/xfs_attr.c' || echo '$(srcdir)/'`xfs/xfs_attr.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-xfs_attr.Tpo xfs/$(DEPDIR)/partclone_xfs-xfs_attr.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/xfs_attr.c' object='xfs/partclone_xfs-xfs_attr.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-xfs_attr.o `test -f 'xfs/xfs_attr.c' || echo '$(srcdir)/'`xfs/xfs_attr.c xfs/partclone_xfs-xfs_attr.obj: xfs/xfs_attr.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-xfs_attr.obj -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-xfs_attr.Tpo -c -o xfs/partclone_xfs-xfs_attr.obj `if test -f 'xfs/xfs_attr.c'; then $(CYGPATH_W) 'xfs/xfs_attr.c'; else $(CYGPATH_W) '$(srcdir)/xfs/xfs_attr.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-xfs_attr.Tpo xfs/$(DEPDIR)/partclone_xfs-xfs_attr.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/xfs_attr.c' object='xfs/partclone_xfs-xfs_attr.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-xfs_attr.obj `if test -f 'xfs/xfs_attr.c'; then $(CYGPATH_W) 'xfs/xfs_attr.c'; else $(CYGPATH_W) '$(srcdir)/xfs/xfs_attr.c'; fi` xfs/partclone_xfs-xfs_dir2_block.o: xfs/xfs_dir2_block.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-xfs_dir2_block.o -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-xfs_dir2_block.Tpo -c -o xfs/partclone_xfs-xfs_dir2_block.o `test -f 'xfs/xfs_dir2_block.c' || echo '$(srcdir)/'`xfs/xfs_dir2_block.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-xfs_dir2_block.Tpo xfs/$(DEPDIR)/partclone_xfs-xfs_dir2_block.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/xfs_dir2_block.c' object='xfs/partclone_xfs-xfs_dir2_block.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-xfs_dir2_block.o `test -f 'xfs/xfs_dir2_block.c' || echo '$(srcdir)/'`xfs/xfs_dir2_block.c xfs/partclone_xfs-xfs_dir2_block.obj: xfs/xfs_dir2_block.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-xfs_dir2_block.obj -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-xfs_dir2_block.Tpo -c -o xfs/partclone_xfs-xfs_dir2_block.obj `if test -f 'xfs/xfs_dir2_block.c'; then $(CYGPATH_W) 'xfs/xfs_dir2_block.c'; else $(CYGPATH_W) '$(srcdir)/xfs/xfs_dir2_block.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-xfs_dir2_block.Tpo xfs/$(DEPDIR)/partclone_xfs-xfs_dir2_block.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/xfs_dir2_block.c' object='xfs/partclone_xfs-xfs_dir2_block.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-xfs_dir2_block.obj `if test -f 'xfs/xfs_dir2_block.c'; then $(CYGPATH_W) 'xfs/xfs_dir2_block.c'; else $(CYGPATH_W) '$(srcdir)/xfs/xfs_dir2_block.c'; fi` xfs/partclone_xfs-cache.o: xfs/cache.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-cache.o -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-cache.Tpo -c -o xfs/partclone_xfs-cache.o `test -f 'xfs/cache.c' || echo '$(srcdir)/'`xfs/cache.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-cache.Tpo xfs/$(DEPDIR)/partclone_xfs-cache.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/cache.c' object='xfs/partclone_xfs-cache.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-cache.o `test -f 'xfs/cache.c' || echo '$(srcdir)/'`xfs/cache.c xfs/partclone_xfs-cache.obj: xfs/cache.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-cache.obj -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-cache.Tpo -c -o xfs/partclone_xfs-cache.obj `if test -f 'xfs/cache.c'; then $(CYGPATH_W) 'xfs/cache.c'; else $(CYGPATH_W) '$(srcdir)/xfs/cache.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-cache.Tpo xfs/$(DEPDIR)/partclone_xfs-cache.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/cache.c' object='xfs/partclone_xfs-cache.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-cache.obj `if test -f 'xfs/cache.c'; then $(CYGPATH_W) 'xfs/cache.c'; else $(CYGPATH_W) '$(srcdir)/xfs/cache.c'; fi` xfs/partclone_xfs-linux.o: xfs/linux.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-linux.o -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-linux.Tpo -c -o xfs/partclone_xfs-linux.o `test -f 'xfs/linux.c' || echo '$(srcdir)/'`xfs/linux.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-linux.Tpo xfs/$(DEPDIR)/partclone_xfs-linux.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/linux.c' object='xfs/partclone_xfs-linux.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-linux.o `test -f 'xfs/linux.c' || echo '$(srcdir)/'`xfs/linux.c xfs/partclone_xfs-linux.obj: xfs/linux.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-linux.obj -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-linux.Tpo -c -o xfs/partclone_xfs-linux.obj `if test -f 'xfs/linux.c'; then $(CYGPATH_W) 'xfs/linux.c'; else $(CYGPATH_W) '$(srcdir)/xfs/linux.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-linux.Tpo xfs/$(DEPDIR)/partclone_xfs-linux.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/linux.c' object='xfs/partclone_xfs-linux.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-linux.obj `if test -f 'xfs/linux.c'; then $(CYGPATH_W) 'xfs/linux.c'; else $(CYGPATH_W) '$(srcdir)/xfs/linux.c'; fi` xfs/partclone_xfs-xfs_attr_leaf.o: xfs/xfs_attr_leaf.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-xfs_attr_leaf.o -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-xfs_attr_leaf.Tpo -c -o xfs/partclone_xfs-xfs_attr_leaf.o `test -f 'xfs/xfs_attr_leaf.c' || echo '$(srcdir)/'`xfs/xfs_attr_leaf.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-xfs_attr_leaf.Tpo xfs/$(DEPDIR)/partclone_xfs-xfs_attr_leaf.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/xfs_attr_leaf.c' object='xfs/partclone_xfs-xfs_attr_leaf.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-xfs_attr_leaf.o `test -f 'xfs/xfs_attr_leaf.c' || echo '$(srcdir)/'`xfs/xfs_attr_leaf.c xfs/partclone_xfs-xfs_attr_leaf.obj: xfs/xfs_attr_leaf.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-xfs_attr_leaf.obj -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-xfs_attr_leaf.Tpo -c -o xfs/partclone_xfs-xfs_attr_leaf.obj `if test -f 'xfs/xfs_attr_leaf.c'; then $(CYGPATH_W) 'xfs/xfs_attr_leaf.c'; else $(CYGPATH_W) '$(srcdir)/xfs/xfs_attr_leaf.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-xfs_attr_leaf.Tpo xfs/$(DEPDIR)/partclone_xfs-xfs_attr_leaf.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/xfs_attr_leaf.c' object='xfs/partclone_xfs-xfs_attr_leaf.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-xfs_attr_leaf.obj `if test -f 'xfs/xfs_attr_leaf.c'; then $(CYGPATH_W) 'xfs/xfs_attr_leaf.c'; else $(CYGPATH_W) '$(srcdir)/xfs/xfs_attr_leaf.c'; fi` xfs/partclone_xfs-xfs_dir2.o: xfs/xfs_dir2.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-xfs_dir2.o -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-xfs_dir2.Tpo -c -o xfs/partclone_xfs-xfs_dir2.o `test -f 'xfs/xfs_dir2.c' || echo '$(srcdir)/'`xfs/xfs_dir2.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-xfs_dir2.Tpo xfs/$(DEPDIR)/partclone_xfs-xfs_dir2.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/xfs_dir2.c' object='xfs/partclone_xfs-xfs_dir2.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-xfs_dir2.o `test -f 'xfs/xfs_dir2.c' || echo '$(srcdir)/'`xfs/xfs_dir2.c xfs/partclone_xfs-xfs_dir2.obj: xfs/xfs_dir2.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-xfs_dir2.obj -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-xfs_dir2.Tpo -c -o xfs/partclone_xfs-xfs_dir2.obj `if test -f 'xfs/xfs_dir2.c'; then $(CYGPATH_W) 'xfs/xfs_dir2.c'; else $(CYGPATH_W) '$(srcdir)/xfs/xfs_dir2.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-xfs_dir2.Tpo xfs/$(DEPDIR)/partclone_xfs-xfs_dir2.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/xfs_dir2.c' object='xfs/partclone_xfs-xfs_dir2.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-xfs_dir2.obj `if test -f 'xfs/xfs_dir2.c'; then $(CYGPATH_W) 'xfs/xfs_dir2.c'; else $(CYGPATH_W) '$(srcdir)/xfs/xfs_dir2.c'; fi` xfs/partclone_xfs-xfs_dir2_data.o: xfs/xfs_dir2_data.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-xfs_dir2_data.o -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-xfs_dir2_data.Tpo -c -o xfs/partclone_xfs-xfs_dir2_data.o `test -f 'xfs/xfs_dir2_data.c' || echo '$(srcdir)/'`xfs/xfs_dir2_data.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-xfs_dir2_data.Tpo xfs/$(DEPDIR)/partclone_xfs-xfs_dir2_data.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/xfs_dir2_data.c' object='xfs/partclone_xfs-xfs_dir2_data.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-xfs_dir2_data.o `test -f 'xfs/xfs_dir2_data.c' || echo '$(srcdir)/'`xfs/xfs_dir2_data.c xfs/partclone_xfs-xfs_dir2_data.obj: xfs/xfs_dir2_data.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-xfs_dir2_data.obj -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-xfs_dir2_data.Tpo -c -o xfs/partclone_xfs-xfs_dir2_data.obj `if test -f 'xfs/xfs_dir2_data.c'; then $(CYGPATH_W) 'xfs/xfs_dir2_data.c'; else $(CYGPATH_W) '$(srcdir)/xfs/xfs_dir2_data.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-xfs_dir2_data.Tpo xfs/$(DEPDIR)/partclone_xfs-xfs_dir2_data.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/xfs_dir2_data.c' object='xfs/partclone_xfs-xfs_dir2_data.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-xfs_dir2_data.obj `if test -f 'xfs/xfs_dir2_data.c'; then $(CYGPATH_W) 'xfs/xfs_dir2_data.c'; else $(CYGPATH_W) '$(srcdir)/xfs/xfs_dir2_data.c'; fi` xfs/partclone_xfs-xfs_attr_remote.o: xfs/xfs_attr_remote.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-xfs_attr_remote.o -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-xfs_attr_remote.Tpo -c -o xfs/partclone_xfs-xfs_attr_remote.o `test -f 'xfs/xfs_attr_remote.c' || echo '$(srcdir)/'`xfs/xfs_attr_remote.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-xfs_attr_remote.Tpo xfs/$(DEPDIR)/partclone_xfs-xfs_attr_remote.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/xfs_attr_remote.c' object='xfs/partclone_xfs-xfs_attr_remote.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-xfs_attr_remote.o `test -f 'xfs/xfs_attr_remote.c' || echo '$(srcdir)/'`xfs/xfs_attr_remote.c xfs/partclone_xfs-xfs_attr_remote.obj: xfs/xfs_attr_remote.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-xfs_attr_remote.obj -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-xfs_attr_remote.Tpo -c -o xfs/partclone_xfs-xfs_attr_remote.obj `if test -f 'xfs/xfs_attr_remote.c'; then $(CYGPATH_W) 'xfs/xfs_attr_remote.c'; else $(CYGPATH_W) '$(srcdir)/xfs/xfs_attr_remote.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-xfs_attr_remote.Tpo xfs/$(DEPDIR)/partclone_xfs-xfs_attr_remote.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/xfs_attr_remote.c' object='xfs/partclone_xfs-xfs_attr_remote.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-xfs_attr_remote.obj `if test -f 'xfs/xfs_attr_remote.c'; then $(CYGPATH_W) 'xfs/xfs_attr_remote.c'; else $(CYGPATH_W) '$(srcdir)/xfs/xfs_attr_remote.c'; fi` xfs/partclone_xfs-xfs_log_rlimit.o: xfs/xfs_log_rlimit.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-xfs_log_rlimit.o -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-xfs_log_rlimit.Tpo -c -o xfs/partclone_xfs-xfs_log_rlimit.o `test -f 'xfs/xfs_log_rlimit.c' || echo '$(srcdir)/'`xfs/xfs_log_rlimit.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-xfs_log_rlimit.Tpo xfs/$(DEPDIR)/partclone_xfs-xfs_log_rlimit.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/xfs_log_rlimit.c' object='xfs/partclone_xfs-xfs_log_rlimit.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-xfs_log_rlimit.o `test -f 'xfs/xfs_log_rlimit.c' || echo '$(srcdir)/'`xfs/xfs_log_rlimit.c xfs/partclone_xfs-xfs_log_rlimit.obj: xfs/xfs_log_rlimit.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-xfs_log_rlimit.obj -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-xfs_log_rlimit.Tpo -c -o xfs/partclone_xfs-xfs_log_rlimit.obj `if test -f 'xfs/xfs_log_rlimit.c'; then $(CYGPATH_W) 'xfs/xfs_log_rlimit.c'; else $(CYGPATH_W) '$(srcdir)/xfs/xfs_log_rlimit.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-xfs_log_rlimit.Tpo xfs/$(DEPDIR)/partclone_xfs-xfs_log_rlimit.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/xfs_log_rlimit.c' object='xfs/partclone_xfs-xfs_log_rlimit.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-xfs_log_rlimit.obj `if test -f 'xfs/xfs_log_rlimit.c'; then $(CYGPATH_W) 'xfs/xfs_log_rlimit.c'; else $(CYGPATH_W) '$(srcdir)/xfs/xfs_log_rlimit.c'; fi` xfs/partclone_xfs-crc32.o: xfs/crc32.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-crc32.o -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-crc32.Tpo -c -o xfs/partclone_xfs-crc32.o `test -f 'xfs/crc32.c' || echo '$(srcdir)/'`xfs/crc32.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-crc32.Tpo xfs/$(DEPDIR)/partclone_xfs-crc32.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/crc32.c' object='xfs/partclone_xfs-crc32.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-crc32.o `test -f 'xfs/crc32.c' || echo '$(srcdir)/'`xfs/crc32.c xfs/partclone_xfs-crc32.obj: xfs/crc32.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-crc32.obj -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-crc32.Tpo -c -o xfs/partclone_xfs-crc32.obj `if test -f 'xfs/crc32.c'; then $(CYGPATH_W) 'xfs/crc32.c'; else $(CYGPATH_W) '$(srcdir)/xfs/crc32.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-crc32.Tpo xfs/$(DEPDIR)/partclone_xfs-crc32.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/crc32.c' object='xfs/partclone_xfs-crc32.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-crc32.obj `if test -f 'xfs/crc32.c'; then $(CYGPATH_W) 'xfs/crc32.c'; else $(CYGPATH_W) '$(srcdir)/xfs/crc32.c'; fi` xfs/partclone_xfs-logitem.o: xfs/logitem.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-logitem.o -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-logitem.Tpo -c -o xfs/partclone_xfs-logitem.o `test -f 'xfs/logitem.c' || echo '$(srcdir)/'`xfs/logitem.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-logitem.Tpo xfs/$(DEPDIR)/partclone_xfs-logitem.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/logitem.c' object='xfs/partclone_xfs-logitem.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-logitem.o `test -f 'xfs/logitem.c' || echo '$(srcdir)/'`xfs/logitem.c xfs/partclone_xfs-logitem.obj: xfs/logitem.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-logitem.obj -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-logitem.Tpo -c -o xfs/partclone_xfs-logitem.obj `if test -f 'xfs/logitem.c'; then $(CYGPATH_W) 'xfs/logitem.c'; else $(CYGPATH_W) '$(srcdir)/xfs/logitem.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-logitem.Tpo xfs/$(DEPDIR)/partclone_xfs-logitem.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/logitem.c' object='xfs/partclone_xfs-logitem.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-logitem.obj `if test -f 'xfs/logitem.c'; then $(CYGPATH_W) 'xfs/logitem.c'; else $(CYGPATH_W) '$(srcdir)/xfs/logitem.c'; fi` xfs/partclone_xfs-xfs_dir2_leaf.o: xfs/xfs_dir2_leaf.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-xfs_dir2_leaf.o -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-xfs_dir2_leaf.Tpo -c -o xfs/partclone_xfs-xfs_dir2_leaf.o `test -f 'xfs/xfs_dir2_leaf.c' || echo '$(srcdir)/'`xfs/xfs_dir2_leaf.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-xfs_dir2_leaf.Tpo xfs/$(DEPDIR)/partclone_xfs-xfs_dir2_leaf.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/xfs_dir2_leaf.c' object='xfs/partclone_xfs-xfs_dir2_leaf.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-xfs_dir2_leaf.o `test -f 'xfs/xfs_dir2_leaf.c' || echo '$(srcdir)/'`xfs/xfs_dir2_leaf.c xfs/partclone_xfs-xfs_dir2_leaf.obj: xfs/xfs_dir2_leaf.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-xfs_dir2_leaf.obj -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-xfs_dir2_leaf.Tpo -c -o xfs/partclone_xfs-xfs_dir2_leaf.obj `if test -f 'xfs/xfs_dir2_leaf.c'; then $(CYGPATH_W) 'xfs/xfs_dir2_leaf.c'; else $(CYGPATH_W) '$(srcdir)/xfs/xfs_dir2_leaf.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-xfs_dir2_leaf.Tpo xfs/$(DEPDIR)/partclone_xfs-xfs_dir2_leaf.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/xfs_dir2_leaf.c' object='xfs/partclone_xfs-xfs_dir2_leaf.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-xfs_dir2_leaf.obj `if test -f 'xfs/xfs_dir2_leaf.c'; then $(CYGPATH_W) 'xfs/xfs_dir2_leaf.c'; else $(CYGPATH_W) '$(srcdir)/xfs/xfs_dir2_leaf.c'; fi` xfs/partclone_xfs-xfs_dir2_node.o: xfs/xfs_dir2_node.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-xfs_dir2_node.o -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-xfs_dir2_node.Tpo -c -o xfs/partclone_xfs-xfs_dir2_node.o `test -f 'xfs/xfs_dir2_node.c' || echo '$(srcdir)/'`xfs/xfs_dir2_node.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-xfs_dir2_node.Tpo xfs/$(DEPDIR)/partclone_xfs-xfs_dir2_node.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/xfs_dir2_node.c' object='xfs/partclone_xfs-xfs_dir2_node.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-xfs_dir2_node.o `test -f 'xfs/xfs_dir2_node.c' || echo '$(srcdir)/'`xfs/xfs_dir2_node.c xfs/partclone_xfs-xfs_dir2_node.obj: xfs/xfs_dir2_node.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-xfs_dir2_node.obj -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-xfs_dir2_node.Tpo -c -o xfs/partclone_xfs-xfs_dir2_node.obj `if test -f 'xfs/xfs_dir2_node.c'; then $(CYGPATH_W) 'xfs/xfs_dir2_node.c'; else $(CYGPATH_W) '$(srcdir)/xfs/xfs_dir2_node.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-xfs_dir2_node.Tpo xfs/$(DEPDIR)/partclone_xfs-xfs_dir2_node.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/xfs_dir2_node.c' object='xfs/partclone_xfs-xfs_dir2_node.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-xfs_dir2_node.obj `if test -f 'xfs/xfs_dir2_node.c'; then $(CYGPATH_W) 'xfs/xfs_dir2_node.c'; else $(CYGPATH_W) '$(srcdir)/xfs/xfs_dir2_node.c'; fi` xfs/partclone_xfs-xfs_bit.o: xfs/xfs_bit.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-xfs_bit.o -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-xfs_bit.Tpo -c -o xfs/partclone_xfs-xfs_bit.o `test -f 'xfs/xfs_bit.c' || echo '$(srcdir)/'`xfs/xfs_bit.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-xfs_bit.Tpo xfs/$(DEPDIR)/partclone_xfs-xfs_bit.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/xfs_bit.c' object='xfs/partclone_xfs-xfs_bit.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-xfs_bit.o `test -f 'xfs/xfs_bit.c' || echo '$(srcdir)/'`xfs/xfs_bit.c xfs/partclone_xfs-xfs_bit.obj: xfs/xfs_bit.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-xfs_bit.obj -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-xfs_bit.Tpo -c -o xfs/partclone_xfs-xfs_bit.obj `if test -f 'xfs/xfs_bit.c'; then $(CYGPATH_W) 'xfs/xfs_bit.c'; else $(CYGPATH_W) '$(srcdir)/xfs/xfs_bit.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-xfs_bit.Tpo xfs/$(DEPDIR)/partclone_xfs-xfs_bit.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/xfs_bit.c' object='xfs/partclone_xfs-xfs_bit.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-xfs_bit.obj `if test -f 'xfs/xfs_bit.c'; then $(CYGPATH_W) 'xfs/xfs_bit.c'; else $(CYGPATH_W) '$(srcdir)/xfs/xfs_bit.c'; fi` xfs/partclone_xfs-xfs_dir2_sf.o: xfs/xfs_dir2_sf.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-xfs_dir2_sf.o -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-xfs_dir2_sf.Tpo -c -o xfs/partclone_xfs-xfs_dir2_sf.o `test -f 'xfs/xfs_dir2_sf.c' || echo '$(srcdir)/'`xfs/xfs_dir2_sf.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-xfs_dir2_sf.Tpo xfs/$(DEPDIR)/partclone_xfs-xfs_dir2_sf.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/xfs_dir2_sf.c' object='xfs/partclone_xfs-xfs_dir2_sf.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-xfs_dir2_sf.o `test -f 'xfs/xfs_dir2_sf.c' || echo '$(srcdir)/'`xfs/xfs_dir2_sf.c xfs/partclone_xfs-xfs_dir2_sf.obj: xfs/xfs_dir2_sf.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-xfs_dir2_sf.obj -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-xfs_dir2_sf.Tpo -c -o xfs/partclone_xfs-xfs_dir2_sf.obj `if test -f 'xfs/xfs_dir2_sf.c'; then $(CYGPATH_W) 'xfs/xfs_dir2_sf.c'; else $(CYGPATH_W) '$(srcdir)/xfs/xfs_dir2_sf.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-xfs_dir2_sf.Tpo xfs/$(DEPDIR)/partclone_xfs-xfs_dir2_sf.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/xfs_dir2_sf.c' object='xfs/partclone_xfs-xfs_dir2_sf.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-xfs_dir2_sf.obj `if test -f 'xfs/xfs_dir2_sf.c'; then $(CYGPATH_W) 'xfs/xfs_dir2_sf.c'; else $(CYGPATH_W) '$(srcdir)/xfs/xfs_dir2_sf.c'; fi` xfs/partclone_xfs-xfs_rtbitmap.o: xfs/xfs_rtbitmap.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-xfs_rtbitmap.o -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-xfs_rtbitmap.Tpo -c -o xfs/partclone_xfs-xfs_rtbitmap.o `test -f 'xfs/xfs_rtbitmap.c' || echo '$(srcdir)/'`xfs/xfs_rtbitmap.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-xfs_rtbitmap.Tpo xfs/$(DEPDIR)/partclone_xfs-xfs_rtbitmap.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/xfs_rtbitmap.c' object='xfs/partclone_xfs-xfs_rtbitmap.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-xfs_rtbitmap.o `test -f 'xfs/xfs_rtbitmap.c' || echo '$(srcdir)/'`xfs/xfs_rtbitmap.c xfs/partclone_xfs-xfs_rtbitmap.obj: xfs/xfs_rtbitmap.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-xfs_rtbitmap.obj -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-xfs_rtbitmap.Tpo -c -o xfs/partclone_xfs-xfs_rtbitmap.obj `if test -f 'xfs/xfs_rtbitmap.c'; then $(CYGPATH_W) 'xfs/xfs_rtbitmap.c'; else $(CYGPATH_W) '$(srcdir)/xfs/xfs_rtbitmap.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-xfs_rtbitmap.Tpo xfs/$(DEPDIR)/partclone_xfs-xfs_rtbitmap.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/xfs_rtbitmap.c' object='xfs/partclone_xfs-xfs_rtbitmap.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-xfs_rtbitmap.obj `if test -f 'xfs/xfs_rtbitmap.c'; then $(CYGPATH_W) 'xfs/xfs_rtbitmap.c'; else $(CYGPATH_W) '$(srcdir)/xfs/xfs_rtbitmap.c'; fi` xfs/partclone_xfs-xfs_bmap_btree.o: xfs/xfs_bmap_btree.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-xfs_bmap_btree.o -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-xfs_bmap_btree.Tpo -c -o xfs/partclone_xfs-xfs_bmap_btree.o `test -f 'xfs/xfs_bmap_btree.c' || echo '$(srcdir)/'`xfs/xfs_bmap_btree.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-xfs_bmap_btree.Tpo xfs/$(DEPDIR)/partclone_xfs-xfs_bmap_btree.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/xfs_bmap_btree.c' object='xfs/partclone_xfs-xfs_bmap_btree.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-xfs_bmap_btree.o `test -f 'xfs/xfs_bmap_btree.c' || echo '$(srcdir)/'`xfs/xfs_bmap_btree.c xfs/partclone_xfs-xfs_bmap_btree.obj: xfs/xfs_bmap_btree.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-xfs_bmap_btree.obj -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-xfs_bmap_btree.Tpo -c -o xfs/partclone_xfs-xfs_bmap_btree.obj `if test -f 'xfs/xfs_bmap_btree.c'; then $(CYGPATH_W) 'xfs/xfs_bmap_btree.c'; else $(CYGPATH_W) '$(srcdir)/xfs/xfs_bmap_btree.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-xfs_bmap_btree.Tpo xfs/$(DEPDIR)/partclone_xfs-xfs_bmap_btree.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/xfs_bmap_btree.c' object='xfs/partclone_xfs-xfs_bmap_btree.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-xfs_bmap_btree.obj `if test -f 'xfs/xfs_bmap_btree.c'; then $(CYGPATH_W) 'xfs/xfs_bmap_btree.c'; else $(CYGPATH_W) '$(srcdir)/xfs/xfs_bmap_btree.c'; fi` xfs/partclone_xfs-xfs_dquot_buf.o: xfs/xfs_dquot_buf.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-xfs_dquot_buf.o -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-xfs_dquot_buf.Tpo -c -o xfs/partclone_xfs-xfs_dquot_buf.o `test -f 'xfs/xfs_dquot_buf.c' || echo '$(srcdir)/'`xfs/xfs_dquot_buf.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-xfs_dquot_buf.Tpo xfs/$(DEPDIR)/partclone_xfs-xfs_dquot_buf.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/xfs_dquot_buf.c' object='xfs/partclone_xfs-xfs_dquot_buf.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-xfs_dquot_buf.o `test -f 'xfs/xfs_dquot_buf.c' || echo '$(srcdir)/'`xfs/xfs_dquot_buf.c xfs/partclone_xfs-xfs_dquot_buf.obj: xfs/xfs_dquot_buf.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-xfs_dquot_buf.obj -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-xfs_dquot_buf.Tpo -c -o xfs/partclone_xfs-xfs_dquot_buf.obj `if test -f 'xfs/xfs_dquot_buf.c'; then $(CYGPATH_W) 'xfs/xfs_dquot_buf.c'; else $(CYGPATH_W) '$(srcdir)/xfs/xfs_dquot_buf.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-xfs_dquot_buf.Tpo xfs/$(DEPDIR)/partclone_xfs-xfs_dquot_buf.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/xfs_dquot_buf.c' object='xfs/partclone_xfs-xfs_dquot_buf.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-xfs_dquot_buf.obj `if test -f 'xfs/xfs_dquot_buf.c'; then $(CYGPATH_W) 'xfs/xfs_dquot_buf.c'; else $(CYGPATH_W) '$(srcdir)/xfs/xfs_dquot_buf.c'; fi` xfs/partclone_xfs-xfs_sb.o: xfs/xfs_sb.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-xfs_sb.o -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-xfs_sb.Tpo -c -o xfs/partclone_xfs-xfs_sb.o `test -f 'xfs/xfs_sb.c' || echo '$(srcdir)/'`xfs/xfs_sb.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-xfs_sb.Tpo xfs/$(DEPDIR)/partclone_xfs-xfs_sb.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/xfs_sb.c' object='xfs/partclone_xfs-xfs_sb.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-xfs_sb.o `test -f 'xfs/xfs_sb.c' || echo '$(srcdir)/'`xfs/xfs_sb.c xfs/partclone_xfs-xfs_sb.obj: xfs/xfs_sb.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-xfs_sb.obj -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-xfs_sb.Tpo -c -o xfs/partclone_xfs-xfs_sb.obj `if test -f 'xfs/xfs_sb.c'; then $(CYGPATH_W) 'xfs/xfs_sb.c'; else $(CYGPATH_W) '$(srcdir)/xfs/xfs_sb.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-xfs_sb.Tpo xfs/$(DEPDIR)/partclone_xfs-xfs_sb.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/xfs_sb.c' object='xfs/partclone_xfs-xfs_sb.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-xfs_sb.obj `if test -f 'xfs/xfs_sb.c'; then $(CYGPATH_W) 'xfs/xfs_sb.c'; else $(CYGPATH_W) '$(srcdir)/xfs/xfs_sb.c'; fi` xfs/partclone_xfs-init.o: xfs/init.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-init.o -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-init.Tpo -c -o xfs/partclone_xfs-init.o `test -f 'xfs/init.c' || echo '$(srcdir)/'`xfs/init.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-init.Tpo xfs/$(DEPDIR)/partclone_xfs-init.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/init.c' object='xfs/partclone_xfs-init.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-init.o `test -f 'xfs/init.c' || echo '$(srcdir)/'`xfs/init.c xfs/partclone_xfs-init.obj: xfs/init.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-init.obj -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-init.Tpo -c -o xfs/partclone_xfs-init.obj `if test -f 'xfs/init.c'; then $(CYGPATH_W) 'xfs/init.c'; else $(CYGPATH_W) '$(srcdir)/xfs/init.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-init.Tpo xfs/$(DEPDIR)/partclone_xfs-init.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/init.c' object='xfs/partclone_xfs-init.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-init.obj `if test -f 'xfs/init.c'; then $(CYGPATH_W) 'xfs/init.c'; else $(CYGPATH_W) '$(srcdir)/xfs/init.c'; fi` xfs/partclone_xfs-radix-tree.o: xfs/radix-tree.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-radix-tree.o -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-radix-tree.Tpo -c -o xfs/partclone_xfs-radix-tree.o `test -f 'xfs/radix-tree.c' || echo '$(srcdir)/'`xfs/radix-tree.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-radix-tree.Tpo xfs/$(DEPDIR)/partclone_xfs-radix-tree.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/radix-tree.c' object='xfs/partclone_xfs-radix-tree.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-radix-tree.o `test -f 'xfs/radix-tree.c' || echo '$(srcdir)/'`xfs/radix-tree.c xfs/partclone_xfs-radix-tree.obj: xfs/radix-tree.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-radix-tree.obj -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-radix-tree.Tpo -c -o xfs/partclone_xfs-radix-tree.obj `if test -f 'xfs/radix-tree.c'; then $(CYGPATH_W) 'xfs/radix-tree.c'; else $(CYGPATH_W) '$(srcdir)/xfs/radix-tree.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-radix-tree.Tpo xfs/$(DEPDIR)/partclone_xfs-radix-tree.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/radix-tree.c' object='xfs/partclone_xfs-radix-tree.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-radix-tree.obj `if test -f 'xfs/radix-tree.c'; then $(CYGPATH_W) 'xfs/radix-tree.c'; else $(CYGPATH_W) '$(srcdir)/xfs/radix-tree.c'; fi` xfs/partclone_xfs-xfs_bmap.o: xfs/xfs_bmap.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-xfs_bmap.o -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-xfs_bmap.Tpo -c -o xfs/partclone_xfs-xfs_bmap.o `test -f 'xfs/xfs_bmap.c' || echo '$(srcdir)/'`xfs/xfs_bmap.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-xfs_bmap.Tpo xfs/$(DEPDIR)/partclone_xfs-xfs_bmap.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/xfs_bmap.c' object='xfs/partclone_xfs-xfs_bmap.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-xfs_bmap.o `test -f 'xfs/xfs_bmap.c' || echo '$(srcdir)/'`xfs/xfs_bmap.c xfs/partclone_xfs-xfs_bmap.obj: xfs/xfs_bmap.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-xfs_bmap.obj -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-xfs_bmap.Tpo -c -o xfs/partclone_xfs-xfs_bmap.obj `if test -f 'xfs/xfs_bmap.c'; then $(CYGPATH_W) 'xfs/xfs_bmap.c'; else $(CYGPATH_W) '$(srcdir)/xfs/xfs_bmap.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-xfs_bmap.Tpo xfs/$(DEPDIR)/partclone_xfs-xfs_bmap.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/xfs_bmap.c' object='xfs/partclone_xfs-xfs_bmap.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-xfs_bmap.obj `if test -f 'xfs/xfs_bmap.c'; then $(CYGPATH_W) 'xfs/xfs_bmap.c'; else $(CYGPATH_W) '$(srcdir)/xfs/xfs_bmap.c'; fi` xfs/partclone_xfs-xfs_symlink_remote.o: xfs/xfs_symlink_remote.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-xfs_symlink_remote.o -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-xfs_symlink_remote.Tpo -c -o xfs/partclone_xfs-xfs_symlink_remote.o `test -f 'xfs/xfs_symlink_remote.c' || echo '$(srcdir)/'`xfs/xfs_symlink_remote.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-xfs_symlink_remote.Tpo xfs/$(DEPDIR)/partclone_xfs-xfs_symlink_remote.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/xfs_symlink_remote.c' object='xfs/partclone_xfs-xfs_symlink_remote.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-xfs_symlink_remote.o `test -f 'xfs/xfs_symlink_remote.c' || echo '$(srcdir)/'`xfs/xfs_symlink_remote.c xfs/partclone_xfs-xfs_symlink_remote.obj: xfs/xfs_symlink_remote.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-xfs_symlink_remote.obj -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-xfs_symlink_remote.Tpo -c -o xfs/partclone_xfs-xfs_symlink_remote.obj `if test -f 'xfs/xfs_symlink_remote.c'; then $(CYGPATH_W) 'xfs/xfs_symlink_remote.c'; else $(CYGPATH_W) '$(srcdir)/xfs/xfs_symlink_remote.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-xfs_symlink_remote.Tpo xfs/$(DEPDIR)/partclone_xfs-xfs_symlink_remote.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/xfs_symlink_remote.c' object='xfs/partclone_xfs-xfs_symlink_remote.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-xfs_symlink_remote.obj `if test -f 'xfs/xfs_symlink_remote.c'; then $(CYGPATH_W) 'xfs/xfs_symlink_remote.c'; else $(CYGPATH_W) '$(srcdir)/xfs/xfs_symlink_remote.c'; fi` xfs/partclone_xfs-rdwr.o: xfs/rdwr.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-rdwr.o -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-rdwr.Tpo -c -o xfs/partclone_xfs-rdwr.o `test -f 'xfs/rdwr.c' || echo '$(srcdir)/'`xfs/rdwr.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-rdwr.Tpo xfs/$(DEPDIR)/partclone_xfs-rdwr.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/rdwr.c' object='xfs/partclone_xfs-rdwr.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-rdwr.o `test -f 'xfs/rdwr.c' || echo '$(srcdir)/'`xfs/rdwr.c xfs/partclone_xfs-rdwr.obj: xfs/rdwr.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-rdwr.obj -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-rdwr.Tpo -c -o xfs/partclone_xfs-rdwr.obj `if test -f 'xfs/rdwr.c'; then $(CYGPATH_W) 'xfs/rdwr.c'; else $(CYGPATH_W) '$(srcdir)/xfs/rdwr.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-rdwr.Tpo xfs/$(DEPDIR)/partclone_xfs-rdwr.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/rdwr.c' object='xfs/partclone_xfs-rdwr.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-rdwr.obj `if test -f 'xfs/rdwr.c'; then $(CYGPATH_W) 'xfs/rdwr.c'; else $(CYGPATH_W) '$(srcdir)/xfs/rdwr.c'; fi` xfs/partclone_xfs-xfs_btree.o: xfs/xfs_btree.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-xfs_btree.o -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-xfs_btree.Tpo -c -o xfs/partclone_xfs-xfs_btree.o `test -f 'xfs/xfs_btree.c' || echo '$(srcdir)/'`xfs/xfs_btree.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-xfs_btree.Tpo xfs/$(DEPDIR)/partclone_xfs-xfs_btree.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/xfs_btree.c' object='xfs/partclone_xfs-xfs_btree.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-xfs_btree.o `test -f 'xfs/xfs_btree.c' || echo '$(srcdir)/'`xfs/xfs_btree.c xfs/partclone_xfs-xfs_btree.obj: xfs/xfs_btree.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-xfs_btree.obj -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-xfs_btree.Tpo -c -o xfs/partclone_xfs-xfs_btree.obj `if test -f 'xfs/xfs_btree.c'; then $(CYGPATH_W) 'xfs/xfs_btree.c'; else $(CYGPATH_W) '$(srcdir)/xfs/xfs_btree.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-xfs_btree.Tpo xfs/$(DEPDIR)/partclone_xfs-xfs_btree.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/xfs_btree.c' object='xfs/partclone_xfs-xfs_btree.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-xfs_btree.obj `if test -f 'xfs/xfs_btree.c'; then $(CYGPATH_W) 'xfs/xfs_btree.c'; else $(CYGPATH_W) '$(srcdir)/xfs/xfs_btree.c'; fi` xfs/partclone_xfs-xfs_ialloc_btree.o: xfs/xfs_ialloc_btree.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-xfs_ialloc_btree.o -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-xfs_ialloc_btree.Tpo -c -o xfs/partclone_xfs-xfs_ialloc_btree.o `test -f 'xfs/xfs_ialloc_btree.c' || echo '$(srcdir)/'`xfs/xfs_ialloc_btree.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-xfs_ialloc_btree.Tpo xfs/$(DEPDIR)/partclone_xfs-xfs_ialloc_btree.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/xfs_ialloc_btree.c' object='xfs/partclone_xfs-xfs_ialloc_btree.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-xfs_ialloc_btree.o `test -f 'xfs/xfs_ialloc_btree.c' || echo '$(srcdir)/'`xfs/xfs_ialloc_btree.c xfs/partclone_xfs-xfs_ialloc_btree.obj: xfs/xfs_ialloc_btree.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-xfs_ialloc_btree.obj -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-xfs_ialloc_btree.Tpo -c -o xfs/partclone_xfs-xfs_ialloc_btree.obj `if test -f 'xfs/xfs_ialloc_btree.c'; then $(CYGPATH_W) 'xfs/xfs_ialloc_btree.c'; else $(CYGPATH_W) '$(srcdir)/xfs/xfs_ialloc_btree.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-xfs_ialloc_btree.Tpo xfs/$(DEPDIR)/partclone_xfs-xfs_ialloc_btree.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/xfs_ialloc_btree.c' object='xfs/partclone_xfs-xfs_ialloc_btree.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-xfs_ialloc_btree.obj `if test -f 'xfs/xfs_ialloc_btree.c'; then $(CYGPATH_W) 'xfs/xfs_ialloc_btree.c'; else $(CYGPATH_W) '$(srcdir)/xfs/xfs_ialloc_btree.c'; fi` xfs/partclone_xfs-trans.o: xfs/trans.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-trans.o -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-trans.Tpo -c -o xfs/partclone_xfs-trans.o `test -f 'xfs/trans.c' || echo '$(srcdir)/'`xfs/trans.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-trans.Tpo xfs/$(DEPDIR)/partclone_xfs-trans.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/trans.c' object='xfs/partclone_xfs-trans.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-trans.o `test -f 'xfs/trans.c' || echo '$(srcdir)/'`xfs/trans.c xfs/partclone_xfs-trans.obj: xfs/trans.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-trans.obj -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-trans.Tpo -c -o xfs/partclone_xfs-trans.obj `if test -f 'xfs/trans.c'; then $(CYGPATH_W) 'xfs/trans.c'; else $(CYGPATH_W) '$(srcdir)/xfs/trans.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-trans.Tpo xfs/$(DEPDIR)/partclone_xfs-trans.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/trans.c' object='xfs/partclone_xfs-trans.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-trans.obj `if test -f 'xfs/trans.c'; then $(CYGPATH_W) 'xfs/trans.c'; else $(CYGPATH_W) '$(srcdir)/xfs/trans.c'; fi` xfs/partclone_xfs-kmem.o: xfs/kmem.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-kmem.o -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-kmem.Tpo -c -o xfs/partclone_xfs-kmem.o `test -f 'xfs/kmem.c' || echo '$(srcdir)/'`xfs/kmem.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-kmem.Tpo xfs/$(DEPDIR)/partclone_xfs-kmem.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/kmem.c' object='xfs/partclone_xfs-kmem.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-kmem.o `test -f 'xfs/kmem.c' || echo '$(srcdir)/'`xfs/kmem.c xfs/partclone_xfs-kmem.obj: xfs/kmem.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-kmem.obj -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-kmem.Tpo -c -o xfs/partclone_xfs-kmem.obj `if test -f 'xfs/kmem.c'; then $(CYGPATH_W) 'xfs/kmem.c'; else $(CYGPATH_W) '$(srcdir)/xfs/kmem.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-kmem.Tpo xfs/$(DEPDIR)/partclone_xfs-kmem.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/kmem.c' object='xfs/partclone_xfs-kmem.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-kmem.obj `if test -f 'xfs/kmem.c'; then $(CYGPATH_W) 'xfs/kmem.c'; else $(CYGPATH_W) '$(srcdir)/xfs/kmem.c'; fi` xfs/partclone_xfs-util.o: xfs/util.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-util.o -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-util.Tpo -c -o xfs/partclone_xfs-util.o `test -f 'xfs/util.c' || echo '$(srcdir)/'`xfs/util.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-util.Tpo xfs/$(DEPDIR)/partclone_xfs-util.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/util.c' object='xfs/partclone_xfs-util.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-util.o `test -f 'xfs/util.c' || echo '$(srcdir)/'`xfs/util.c xfs/partclone_xfs-util.obj: xfs/util.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-util.obj -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-util.Tpo -c -o xfs/partclone_xfs-util.obj `if test -f 'xfs/util.c'; then $(CYGPATH_W) 'xfs/util.c'; else $(CYGPATH_W) '$(srcdir)/xfs/util.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-util.Tpo xfs/$(DEPDIR)/partclone_xfs-util.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/util.c' object='xfs/partclone_xfs-util.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-util.obj `if test -f 'xfs/util.c'; then $(CYGPATH_W) 'xfs/util.c'; else $(CYGPATH_W) '$(srcdir)/xfs/util.c'; fi` xfs/partclone_xfs-xfs_ialloc.o: xfs/xfs_ialloc.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-xfs_ialloc.o -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-xfs_ialloc.Tpo -c -o xfs/partclone_xfs-xfs_ialloc.o `test -f 'xfs/xfs_ialloc.c' || echo '$(srcdir)/'`xfs/xfs_ialloc.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-xfs_ialloc.Tpo xfs/$(DEPDIR)/partclone_xfs-xfs_ialloc.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/xfs_ialloc.c' object='xfs/partclone_xfs-xfs_ialloc.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-xfs_ialloc.o `test -f 'xfs/xfs_ialloc.c' || echo '$(srcdir)/'`xfs/xfs_ialloc.c xfs/partclone_xfs-xfs_ialloc.obj: xfs/xfs_ialloc.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-xfs_ialloc.obj -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-xfs_ialloc.Tpo -c -o xfs/partclone_xfs-xfs_ialloc.obj `if test -f 'xfs/xfs_ialloc.c'; then $(CYGPATH_W) 'xfs/xfs_ialloc.c'; else $(CYGPATH_W) '$(srcdir)/xfs/xfs_ialloc.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-xfs_ialloc.Tpo xfs/$(DEPDIR)/partclone_xfs-xfs_ialloc.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/xfs_ialloc.c' object='xfs/partclone_xfs-xfs_ialloc.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-xfs_ialloc.obj `if test -f 'xfs/xfs_ialloc.c'; then $(CYGPATH_W) 'xfs/xfs_ialloc.c'; else $(CYGPATH_W) '$(srcdir)/xfs/xfs_ialloc.c'; fi` xfs/partclone_xfs-xfs_trans_resv.o: xfs/xfs_trans_resv.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-xfs_trans_resv.o -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-xfs_trans_resv.Tpo -c -o xfs/partclone_xfs-xfs_trans_resv.o `test -f 'xfs/xfs_trans_resv.c' || echo '$(srcdir)/'`xfs/xfs_trans_resv.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-xfs_trans_resv.Tpo xfs/$(DEPDIR)/partclone_xfs-xfs_trans_resv.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/xfs_trans_resv.c' object='xfs/partclone_xfs-xfs_trans_resv.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-xfs_trans_resv.o `test -f 'xfs/xfs_trans_resv.c' || echo '$(srcdir)/'`xfs/xfs_trans_resv.c xfs/partclone_xfs-xfs_trans_resv.obj: xfs/xfs_trans_resv.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-xfs_trans_resv.obj -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-xfs_trans_resv.Tpo -c -o xfs/partclone_xfs-xfs_trans_resv.obj `if test -f 'xfs/xfs_trans_resv.c'; then $(CYGPATH_W) 'xfs/xfs_trans_resv.c'; else $(CYGPATH_W) '$(srcdir)/xfs/xfs_trans_resv.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-xfs_trans_resv.Tpo xfs/$(DEPDIR)/partclone_xfs-xfs_trans_resv.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/xfs_trans_resv.c' object='xfs/partclone_xfs-xfs_trans_resv.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-xfs_trans_resv.obj `if test -f 'xfs/xfs_trans_resv.c'; then $(CYGPATH_W) 'xfs/xfs_trans_resv.c'; else $(CYGPATH_W) '$(srcdir)/xfs/xfs_trans_resv.c'; fi` xfs/partclone_xfs-xfs_alloc_btree.o: xfs/xfs_alloc_btree.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-xfs_alloc_btree.o -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-xfs_alloc_btree.Tpo -c -o xfs/partclone_xfs-xfs_alloc_btree.o `test -f 'xfs/xfs_alloc_btree.c' || echo '$(srcdir)/'`xfs/xfs_alloc_btree.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-xfs_alloc_btree.Tpo xfs/$(DEPDIR)/partclone_xfs-xfs_alloc_btree.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/xfs_alloc_btree.c' object='xfs/partclone_xfs-xfs_alloc_btree.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-xfs_alloc_btree.o `test -f 'xfs/xfs_alloc_btree.c' || echo '$(srcdir)/'`xfs/xfs_alloc_btree.c xfs/partclone_xfs-xfs_alloc_btree.obj: xfs/xfs_alloc_btree.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-xfs_alloc_btree.obj -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-xfs_alloc_btree.Tpo -c -o xfs/partclone_xfs-xfs_alloc_btree.obj `if test -f 'xfs/xfs_alloc_btree.c'; then $(CYGPATH_W) 'xfs/xfs_alloc_btree.c'; else $(CYGPATH_W) '$(srcdir)/xfs/xfs_alloc_btree.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-xfs_alloc_btree.Tpo xfs/$(DEPDIR)/partclone_xfs-xfs_alloc_btree.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/xfs_alloc_btree.c' object='xfs/partclone_xfs-xfs_alloc_btree.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-xfs_alloc_btree.obj `if test -f 'xfs/xfs_alloc_btree.c'; then $(CYGPATH_W) 'xfs/xfs_alloc_btree.c'; else $(CYGPATH_W) '$(srcdir)/xfs/xfs_alloc_btree.c'; fi` xfs/partclone_xfs-xfs_da_btree.o: xfs/xfs_da_btree.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-xfs_da_btree.o -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-xfs_da_btree.Tpo -c -o xfs/partclone_xfs-xfs_da_btree.o `test -f 'xfs/xfs_da_btree.c' || echo '$(srcdir)/'`xfs/xfs_da_btree.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-xfs_da_btree.Tpo xfs/$(DEPDIR)/partclone_xfs-xfs_da_btree.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/xfs_da_btree.c' object='xfs/partclone_xfs-xfs_da_btree.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-xfs_da_btree.o `test -f 'xfs/xfs_da_btree.c' || echo '$(srcdir)/'`xfs/xfs_da_btree.c xfs/partclone_xfs-xfs_da_btree.obj: xfs/xfs_da_btree.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-xfs_da_btree.obj -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-xfs_da_btree.Tpo -c -o xfs/partclone_xfs-xfs_da_btree.obj `if test -f 'xfs/xfs_da_btree.c'; then $(CYGPATH_W) 'xfs/xfs_da_btree.c'; else $(CYGPATH_W) '$(srcdir)/xfs/xfs_da_btree.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-xfs_da_btree.Tpo xfs/$(DEPDIR)/partclone_xfs-xfs_da_btree.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/xfs_da_btree.c' object='xfs/partclone_xfs-xfs_da_btree.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-xfs_da_btree.obj `if test -f 'xfs/xfs_da_btree.c'; then $(CYGPATH_W) 'xfs/xfs_da_btree.c'; else $(CYGPATH_W) '$(srcdir)/xfs/xfs_da_btree.c'; fi` xfs/partclone_xfs-xfs_inode_buf.o: xfs/xfs_inode_buf.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-xfs_inode_buf.o -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-xfs_inode_buf.Tpo -c -o xfs/partclone_xfs-xfs_inode_buf.o `test -f 'xfs/xfs_inode_buf.c' || echo '$(srcdir)/'`xfs/xfs_inode_buf.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-xfs_inode_buf.Tpo xfs/$(DEPDIR)/partclone_xfs-xfs_inode_buf.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/xfs_inode_buf.c' object='xfs/partclone_xfs-xfs_inode_buf.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-xfs_inode_buf.o `test -f 'xfs/xfs_inode_buf.c' || echo '$(srcdir)/'`xfs/xfs_inode_buf.c xfs/partclone_xfs-xfs_inode_buf.obj: xfs/xfs_inode_buf.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-xfs_inode_buf.obj -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-xfs_inode_buf.Tpo -c -o xfs/partclone_xfs-xfs_inode_buf.obj `if test -f 'xfs/xfs_inode_buf.c'; then $(CYGPATH_W) 'xfs/xfs_inode_buf.c'; else $(CYGPATH_W) '$(srcdir)/xfs/xfs_inode_buf.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-xfs_inode_buf.Tpo xfs/$(DEPDIR)/partclone_xfs-xfs_inode_buf.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/xfs_inode_buf.c' object='xfs/partclone_xfs-xfs_inode_buf.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-xfs_inode_buf.obj `if test -f 'xfs/xfs_inode_buf.c'; then $(CYGPATH_W) 'xfs/xfs_inode_buf.c'; else $(CYGPATH_W) '$(srcdir)/xfs/xfs_inode_buf.c'; fi` xfs/partclone_xfs-xfs_alloc.o: xfs/xfs_alloc.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-xfs_alloc.o -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-xfs_alloc.Tpo -c -o xfs/partclone_xfs-xfs_alloc.o `test -f 'xfs/xfs_alloc.c' || echo '$(srcdir)/'`xfs/xfs_alloc.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-xfs_alloc.Tpo xfs/$(DEPDIR)/partclone_xfs-xfs_alloc.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/xfs_alloc.c' object='xfs/partclone_xfs-xfs_alloc.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-xfs_alloc.o `test -f 'xfs/xfs_alloc.c' || echo '$(srcdir)/'`xfs/xfs_alloc.c xfs/partclone_xfs-xfs_alloc.obj: xfs/xfs_alloc.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-xfs_alloc.obj -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-xfs_alloc.Tpo -c -o xfs/partclone_xfs-xfs_alloc.obj `if test -f 'xfs/xfs_alloc.c'; then $(CYGPATH_W) 'xfs/xfs_alloc.c'; else $(CYGPATH_W) '$(srcdir)/xfs/xfs_alloc.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-xfs_alloc.Tpo xfs/$(DEPDIR)/partclone_xfs-xfs_alloc.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/xfs_alloc.c' object='xfs/partclone_xfs-xfs_alloc.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-xfs_alloc.obj `if test -f 'xfs/xfs_alloc.c'; then $(CYGPATH_W) 'xfs/xfs_alloc.c'; else $(CYGPATH_W) '$(srcdir)/xfs/xfs_alloc.c'; fi` xfs/partclone_xfs-xfs_da_format.o: xfs/xfs_da_format.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-xfs_da_format.o -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-xfs_da_format.Tpo -c -o xfs/partclone_xfs-xfs_da_format.o `test -f 'xfs/xfs_da_format.c' || echo '$(srcdir)/'`xfs/xfs_da_format.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-xfs_da_format.Tpo xfs/$(DEPDIR)/partclone_xfs-xfs_da_format.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/xfs_da_format.c' object='xfs/partclone_xfs-xfs_da_format.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-xfs_da_format.o `test -f 'xfs/xfs_da_format.c' || echo '$(srcdir)/'`xfs/xfs_da_format.c xfs/partclone_xfs-xfs_da_format.obj: xfs/xfs_da_format.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-xfs_da_format.obj -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-xfs_da_format.Tpo -c -o xfs/partclone_xfs-xfs_da_format.obj `if test -f 'xfs/xfs_da_format.c'; then $(CYGPATH_W) 'xfs/xfs_da_format.c'; else $(CYGPATH_W) '$(srcdir)/xfs/xfs_da_format.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-xfs_da_format.Tpo xfs/$(DEPDIR)/partclone_xfs-xfs_da_format.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/xfs_da_format.c' object='xfs/partclone_xfs-xfs_da_format.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-xfs_da_format.obj `if test -f 'xfs/xfs_da_format.c'; then $(CYGPATH_W) 'xfs/xfs_da_format.c'; else $(CYGPATH_W) '$(srcdir)/xfs/xfs_da_format.c'; fi` xfs/partclone_xfs-xfs_inode_fork.o: xfs/xfs_inode_fork.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-xfs_inode_fork.o -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-xfs_inode_fork.Tpo -c -o xfs/partclone_xfs-xfs_inode_fork.o `test -f 'xfs/xfs_inode_fork.c' || echo '$(srcdir)/'`xfs/xfs_inode_fork.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-xfs_inode_fork.Tpo xfs/$(DEPDIR)/partclone_xfs-xfs_inode_fork.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/xfs_inode_fork.c' object='xfs/partclone_xfs-xfs_inode_fork.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-xfs_inode_fork.o `test -f 'xfs/xfs_inode_fork.c' || echo '$(srcdir)/'`xfs/xfs_inode_fork.c xfs/partclone_xfs-xfs_inode_fork.obj: xfs/xfs_inode_fork.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -MT xfs/partclone_xfs-xfs_inode_fork.obj -MD -MP -MF xfs/$(DEPDIR)/partclone_xfs-xfs_inode_fork.Tpo -c -o xfs/partclone_xfs-xfs_inode_fork.obj `if test -f 'xfs/xfs_inode_fork.c'; then $(CYGPATH_W) 'xfs/xfs_inode_fork.c'; else $(CYGPATH_W) '$(srcdir)/xfs/xfs_inode_fork.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) xfs/$(DEPDIR)/partclone_xfs-xfs_inode_fork.Tpo xfs/$(DEPDIR)/partclone_xfs-xfs_inode_fork.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xfs/xfs_inode_fork.c' object='xfs/partclone_xfs-xfs_inode_fork.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(partclone_xfs_CFLAGS) $(CFLAGS) -c -o xfs/partclone_xfs-xfs_inode_fork.obj `if test -f 'xfs/xfs_inode_fork.c'; then $(CYGPATH_W) 'xfs/xfs_inode_fork.c'; else $(CYGPATH_W) '$(srcdir)/xfs/xfs_inode_fork.c'; fi` ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) installdirs: for dir in "$(DESTDIR)$(sbindir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) -rm -f btrfs/$(DEPDIR)/$(am__dirstamp) -rm -f btrfs/$(am__dirstamp) -rm -f exfat/$(DEPDIR)/$(am__dirstamp) -rm -f exfat/$(am__dirstamp) -rm -f f2fs/$(DEPDIR)/$(am__dirstamp) -rm -f f2fs/$(am__dirstamp) -rm -f xfs/$(DEPDIR)/$(am__dirstamp) -rm -f xfs/$(am__dirstamp) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-sbinPROGRAMS mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) btrfs/$(DEPDIR) exfat/$(DEPDIR) f2fs/$(DEPDIR) xfs/$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-sbinPROGRAMS @$(NORMAL_INSTALL) $(MAKE) $(AM_MAKEFLAGS) install-exec-hook install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) btrfs/$(DEPDIR) exfat/$(DEPDIR) f2fs/$(DEPDIR) xfs/$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-local uninstall-sbinPROGRAMS .MAKE: install-am install-exec-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-sbinPROGRAMS cscopelist-am ctags ctags-am distclean \ distclean-compile distclean-generic distclean-tags distdir dvi \ dvi-am html html-am info info-am install install-am \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-exec-hook install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-sbinPROGRAMS install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-local uninstall-sbinPROGRAMS .PRECIOUS: Makefile version.h: FORCE $(TOOLBOX) --update-version # Extra install-exec-hook: @ENABLE_EXTFS_TRUE@ $(LN_S) -f partclone.extfs $(DESTDIR)$(sbindir)/partclone.ext2 @ENABLE_EXTFS_TRUE@ $(LN_S) -f partclone.extfs $(DESTDIR)$(sbindir)/partclone.ext3 @ENABLE_EXTFS_TRUE@ $(LN_S) -f partclone.extfs $(DESTDIR)$(sbindir)/partclone.ext4 @ENABLE_EXTFS_TRUE@ $(LN_S) -f partclone.extfs $(DESTDIR)$(sbindir)/partclone.ext4dev @ENABLE_HFSP_TRUE@ $(LN_S) -f partclone.hfsp $(DESTDIR)$(sbindir)/partclone.hfs+ @ENABLE_HFSP_TRUE@ $(LN_S) -f partclone.hfsp $(DESTDIR)$(sbindir)/partclone.hfsplus @ENABLE_NTFS_TRUE@ $(LN_S) -f partclone.ntfsfixboot $(DESTDIR)$(sbindir)/partclone.ntfsreloc @ENABLE_FAT_TRUE@ $(LN_S) -f partclone.fat $(DESTDIR)$(sbindir)/partclone.fat12 @ENABLE_FAT_TRUE@ $(LN_S) -f partclone.fat $(DESTDIR)$(sbindir)/partclone.fat16 @ENABLE_FAT_TRUE@ $(LN_S) -f partclone.fat $(DESTDIR)$(sbindir)/partclone.fat32 @ENABLE_FAT_TRUE@ $(LN_S) -f partclone.fat $(DESTDIR)$(sbindir)/partclone.vfat @ENABLE_VMFS_TRUE@ $(LN_S) -f partclone.vmfs $(DESTDIR)$(sbindir)/partclone.VMFS_volume_member @ENABLE_VMFS_TRUE@ $(LN_S) -f partclone.vmfs $(DESTDIR)$(sbindir)/partclone.vmfs3 # $(LN_S) -f partclone.vmfs $(DESTDIR)$(sbindir)/partclone.vmfs5 uninstall-local: @ENABLE_EXTFS_TRUE@ $(RM) -f $(sbindir)/partclone.ext4dev @ENABLE_EXTFS_TRUE@ $(RM) -f $(sbindir)/partclone.ext4 @ENABLE_EXTFS_TRUE@ $(RM) -f $(sbindir)/partclone.ext3 @ENABLE_EXTFS_TRUE@ $(RM) -f $(sbindir)/partclone.ext2 @ENABLE_HFSP_TRUE@ $(RM) -f $(sbindir)/partclone.hfs+ @ENABLE_HFSP_TRUE@ $(RM) -f $(sbindir)/partclone.hfsplus @ENABLE_FAT_TRUE@ $(RM) -f $(sbindir)/partclone.fat12 @ENABLE_FAT_TRUE@ $(RM) -f $(sbindir)/partclone.fat16 @ENABLE_FAT_TRUE@ $(RM) -f $(sbindir)/partclone.fat32 @ENABLE_FAT_TRUE@ $(RM) -f $(sbindir)/partclone.vfat @ENABLE_NTFS_TRUE@ $(RM) -f $(sbindir)/partclone.ntfsreloc @ENABLE_VMFS_TRUE@ $(RM) -f $(sbindir)/partclone.VMFS_volume_member FORCE: # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: partclone-0.2.86/src/bitmap.h000066400000000000000000000014021262102574200160100ustar00rootroot00000000000000#define PART_BITS_PER_LONG ((int)sizeof(unsigned long)*8) #define LONGS(bits) (((bits)+PART_BITS_PER_LONG-1)/PART_BITS_PER_LONG) static inline int pc_test_bit(unsigned long int nr, unsigned long *bitmap) { unsigned long offset = nr / PART_BITS_PER_LONG; unsigned long bit = nr & (PART_BITS_PER_LONG-1); return (bitmap[offset] >> bit) & 1; } static inline void pc_set_bit(unsigned long int nr, unsigned long *bitmap) { unsigned long offset = nr / PART_BITS_PER_LONG; unsigned long bit = nr & (PART_BITS_PER_LONG-1); bitmap[offset] |= 1UL << bit; } static inline void pc_clear_bit(unsigned long int nr, unsigned long *bitmap) { unsigned long offset = nr / PART_BITS_PER_LONG; unsigned long bit = nr & (PART_BITS_PER_LONG-1); bitmap[offset] &= ~(1UL << bit); } partclone-0.2.86/src/btrfs/000077500000000000000000000000001262102574200155065ustar00rootroot00000000000000partclone-0.2.86/src/btrfs/bitops.h000066400000000000000000000121061262102574200171570ustar00rootroot00000000000000#ifndef _PERF_LINUX_BITOPS_H_ #define _PERF_LINUX_BITOPS_H_ #include #define BITS_PER_BYTE 8 #define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long)) #define BITS_TO_U64(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u64)) #define BITS_TO_U32(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u32)) #define for_each_set_bit(bit, addr, size) \ for ((bit) = find_first_bit((addr), (size)); \ (bit) < (size); \ (bit) = find_next_bit((addr), (size), (bit) + 1)) /* same as for_each_set_bit() but use bit as value to start with */ #define for_each_set_bit_from(bit, addr, size) \ for ((bit) = find_next_bit((addr), (size), (bit)); \ (bit) < (size); \ (bit) = find_next_bit((addr), (size), (bit) + 1)) static inline void set_bit(int nr, unsigned long *addr) { addr[nr / BITS_PER_LONG] |= 1UL << (nr % BITS_PER_LONG); } static inline void clear_bit(int nr, unsigned long *addr) { addr[nr / BITS_PER_LONG] &= ~(1UL << (nr % BITS_PER_LONG)); } /** * hweightN - returns the hamming weight of a N-bit word * @x: the word to weigh * * The Hamming Weight of a number is the total number of bits set in it. */ static inline unsigned int hweight32(unsigned int w) { unsigned int res = w - ((w >> 1) & 0x55555555); res = (res & 0x33333333) + ((res >> 2) & 0x33333333); res = (res + (res >> 4)) & 0x0F0F0F0F; res = res + (res >> 8); return (res + (res >> 16)) & 0x000000FF; } static inline unsigned long hweight64(__u64 w) { #if BITS_PER_LONG == 32 return hweight32((unsigned int)(w >> 32)) + hweight32((unsigned int)w); #elif BITS_PER_LONG == 64 __u64 res = w - ((w >> 1) & 0x5555555555555555ul); res = (res & 0x3333333333333333ul) + ((res >> 2) & 0x3333333333333333ul); res = (res + (res >> 4)) & 0x0F0F0F0F0F0F0F0Ful; res = res + (res >> 8); res = res + (res >> 16); return (res + (res >> 32)) & 0x00000000000000FFul; #endif } static inline unsigned long hweight_long(unsigned long w) { return sizeof(w) == 4 ? hweight32(w) : hweight64(w); } #define BITOP_WORD(nr) ((nr) / BITS_PER_LONG) /** * __ffs - find first bit in word. * @word: The word to search * * Undefined if no bit exists, so code should check against 0 first. */ static __always_inline unsigned long __ffs(unsigned long word) { int num = 0; #if BITS_PER_LONG == 64 if ((word & 0xffffffff) == 0) { num += 32; word >>= 32; } #endif if ((word & 0xffff) == 0) { num += 16; word >>= 16; } if ((word & 0xff) == 0) { num += 8; word >>= 8; } if ((word & 0xf) == 0) { num += 4; word >>= 4; } if ((word & 0x3) == 0) { num += 2; word >>= 2; } if ((word & 0x1) == 0) num += 1; return num; } #define ffz(x) __ffs(~(x)) /* * Find the first set bit in a memory region. */ static inline unsigned long find_first_bit(const unsigned long *addr, unsigned long size) { const unsigned long *p = addr; unsigned long result = 0; unsigned long tmp; while (size & ~(BITS_PER_LONG-1)) { if ((tmp = *(p++))) goto found; result += BITS_PER_LONG; size -= BITS_PER_LONG; } if (!size) return result; tmp = (*p) & (~0UL >> (BITS_PER_LONG - size)); if (tmp == 0UL) /* Are any bits set? */ return result + size; /* Nope. */ found: return result + __ffs(tmp); } /* * Find the next set bit in a memory region. */ static inline unsigned long find_next_bit(const unsigned long *addr, unsigned long size, unsigned long offset) { const unsigned long *p = addr + BITOP_WORD(offset); unsigned long result = offset & ~(BITS_PER_LONG-1); unsigned long tmp; if (offset >= size) return size; size -= result; offset %= BITS_PER_LONG; if (offset) { tmp = *(p++); tmp &= (~0UL << offset); if (size < BITS_PER_LONG) goto found_first; if (tmp) goto found_middle; size -= BITS_PER_LONG; result += BITS_PER_LONG; } while (size & ~(BITS_PER_LONG-1)) { if ((tmp = *(p++))) goto found_middle; result += BITS_PER_LONG; size -= BITS_PER_LONG; } if (!size) return result; tmp = *p; found_first: tmp &= (~0UL >> (BITS_PER_LONG - size)); if (tmp == 0UL) /* Are any bits set? */ return result + size; /* Nope. */ found_middle: return result + __ffs(tmp); } /* * This implementation of find_{first,next}_zero_bit was stolen from * Linus' asm-alpha/bitops.h. */ static inline unsigned long find_next_zero_bit(const unsigned long *addr, unsigned long size, unsigned long offset) { const unsigned long *p = addr + BITOP_WORD(offset); unsigned long result = offset & ~(BITS_PER_LONG-1); unsigned long tmp; if (offset >= size) return size; size -= result; offset %= BITS_PER_LONG; if (offset) { tmp = *(p++); tmp |= ~0UL >> (BITS_PER_LONG - offset); if (size < BITS_PER_LONG) goto found_first; if (~tmp) goto found_middle; size -= BITS_PER_LONG; result += BITS_PER_LONG; } while (size & ~(BITS_PER_LONG-1)) { if (~(tmp = *(p++))) goto found_middle; result += BITS_PER_LONG; size -= BITS_PER_LONG; } if (!size) return result; tmp = *p; found_first: tmp |= ~0UL << size; if (tmp == ~0UL) /* Are any bits zero? */ return result + size; /* Nope. */ found_middle: return result + ffz(tmp); } #endif partclone-0.2.86/src/btrfs/btrfs-list.c000066400000000000000000001241101262102574200177420ustar00rootroot00000000000000/* * Copyright (C) 2010 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. */ #define _GNU_SOURCE #include #include #include "ioctl.h" #include #include #include #include #include #include #include #include #include "ctree.h" #include "transaction.h" #include "utils.h" #include #include "btrfs-list.h" #include "rbtree-utils.h" #define BTRFS_LIST_NFILTERS_INCREASE (2 * BTRFS_LIST_FILTER_MAX) #define BTRFS_LIST_NCOMPS_INCREASE (2 * BTRFS_LIST_COMP_MAX) /* we store all the roots we find in an rbtree so that we can * search for them later. */ struct root_lookup { struct rb_root root; }; static struct { char *name; char *column_name; int need_print; } btrfs_list_columns[] = { { .name = "ID", .column_name = "ID", .need_print = 0, }, { .name = "gen", .column_name = "Gen", .need_print = 0, }, { .name = "cgen", .column_name = "CGen", .need_print = 0, }, { .name = "parent", .column_name = "Parent", .need_print = 0, }, { .name = "top level", .column_name = "Top Level", .need_print = 0, }, { .name = "otime", .column_name = "OTime", .need_print = 0, }, { .name = "parent_uuid", .column_name = "Parent UUID", .need_print = 0, }, { .name = "received_uuid", .column_name = "Received UUID", .need_print = 0, }, { .name = "uuid", .column_name = "UUID", .need_print = 0, }, { .name = "path", .column_name = "Path", .need_print = 0, }, { .name = NULL, .column_name = NULL, .need_print = 0, }, }; static btrfs_list_filter_func all_filter_funcs[]; static btrfs_list_comp_func all_comp_funcs[]; void btrfs_list_setup_print_column(enum btrfs_list_column_enum column) { int i; BUG_ON(column < 0 || column > BTRFS_LIST_ALL); if (column < BTRFS_LIST_ALL) { btrfs_list_columns[column].need_print = 1; return; } for (i = 0; i < BTRFS_LIST_ALL; i++) btrfs_list_columns[i].need_print = 1; } static void root_lookup_init(struct root_lookup *tree) { tree->root.rb_node = NULL; } static int comp_entry_with_rootid(struct root_info *entry1, struct root_info *entry2, int is_descending) { int ret; if (entry1->root_id > entry2->root_id) ret = 1; else if (entry1->root_id < entry2->root_id) ret = -1; else ret = 0; return is_descending ? -ret : ret; } static int comp_entry_with_gen(struct root_info *entry1, struct root_info *entry2, int is_descending) { int ret; if (entry1->gen > entry2->gen) ret = 1; else if (entry1->gen < entry2->gen) ret = -1; else ret = 0; return is_descending ? -ret : ret; } static int comp_entry_with_ogen(struct root_info *entry1, struct root_info *entry2, int is_descending) { int ret; if (entry1->ogen > entry2->ogen) ret = 1; else if (entry1->ogen < entry2->ogen) ret = -1; else ret = 0; return is_descending ? -ret : ret; } static int comp_entry_with_path(struct root_info *entry1, struct root_info *entry2, int is_descending) { int ret; if (strcmp(entry1->full_path, entry2->full_path) > 0) ret = 1; else if (strcmp(entry1->full_path, entry2->full_path) < 0) ret = -1; else ret = 0; return is_descending ? -ret : ret; } static btrfs_list_comp_func all_comp_funcs[] = { [BTRFS_LIST_COMP_ROOTID] = comp_entry_with_rootid, [BTRFS_LIST_COMP_OGEN] = comp_entry_with_ogen, [BTRFS_LIST_COMP_GEN] = comp_entry_with_gen, [BTRFS_LIST_COMP_PATH] = comp_entry_with_path, }; static char *all_sort_items[] = { [BTRFS_LIST_COMP_ROOTID] = "rootid", [BTRFS_LIST_COMP_OGEN] = "ogen", [BTRFS_LIST_COMP_GEN] = "gen", [BTRFS_LIST_COMP_PATH] = "path", [BTRFS_LIST_COMP_MAX] = NULL, }; static int btrfs_list_get_sort_item(char *sort_name) { int i; for (i = 0; i < BTRFS_LIST_COMP_MAX; i++) { if (strcmp(sort_name, all_sort_items[i]) == 0) return i; } return -1; } struct btrfs_list_comparer_set *btrfs_list_alloc_comparer_set(void) { struct btrfs_list_comparer_set *set; int size; size = sizeof(struct btrfs_list_comparer_set) + BTRFS_LIST_NCOMPS_INCREASE * sizeof(struct btrfs_list_comparer); set = malloc(size); if (!set) { fprintf(stderr, "memory allocation failed\n"); exit(1); } memset(set, 0, size); set->total = BTRFS_LIST_NCOMPS_INCREASE; return set; } void btrfs_list_free_comparer_set(struct btrfs_list_comparer_set *comp_set) { free(comp_set); } static int btrfs_list_setup_comparer(struct btrfs_list_comparer_set **comp_set, enum btrfs_list_comp_enum comparer, int is_descending) { struct btrfs_list_comparer_set *set = *comp_set; int size; BUG_ON(!set); BUG_ON(comparer >= BTRFS_LIST_COMP_MAX); BUG_ON(set->ncomps > set->total); if (set->ncomps == set->total) { size = set->total + BTRFS_LIST_NCOMPS_INCREASE; size = sizeof(*set) + size * sizeof(struct btrfs_list_comparer); set = realloc(set, size); if (!set) { fprintf(stderr, "memory allocation failed\n"); exit(1); } memset(&set->comps[set->total], 0, BTRFS_LIST_NCOMPS_INCREASE * sizeof(struct btrfs_list_comparer)); set->total += BTRFS_LIST_NCOMPS_INCREASE; *comp_set = set; } BUG_ON(set->comps[set->ncomps].comp_func); set->comps[set->ncomps].comp_func = all_comp_funcs[comparer]; set->comps[set->ncomps].is_descending = is_descending; set->ncomps++; return 0; } static int sort_comp(struct root_info *entry1, struct root_info *entry2, struct btrfs_list_comparer_set *set) { int rootid_compared = 0; int i, ret = 0; if (!set || !set->ncomps) goto comp_rootid; for (i = 0; i < set->ncomps; i++) { if (!set->comps[i].comp_func) break; ret = set->comps[i].comp_func(entry1, entry2, set->comps[i].is_descending); if (ret) return ret; if (set->comps[i].comp_func == comp_entry_with_rootid) rootid_compared = 1; } if (!rootid_compared) { comp_rootid: ret = comp_entry_with_rootid(entry1, entry2, 0); } return ret; } static int sort_tree_insert(struct root_lookup *sort_tree, struct root_info *ins, struct btrfs_list_comparer_set *comp_set) { struct rb_node **p = &sort_tree->root.rb_node; struct rb_node *parent = NULL; struct root_info *curr; int ret; while (*p) { parent = *p; curr = rb_entry(parent, struct root_info, sort_node); ret = sort_comp(ins, curr, comp_set); if (ret < 0) p = &(*p)->rb_left; else if (ret > 0) p = &(*p)->rb_right; else return -EEXIST; } rb_link_node(&ins->sort_node, parent, p); rb_insert_color(&ins->sort_node, &sort_tree->root); return 0; } /* * insert a new root into the tree. returns the existing root entry * if one is already there. Both root_id and ref_tree are used * as the key */ static int root_tree_insert(struct root_lookup *root_tree, struct root_info *ins) { struct rb_node **p = &root_tree->root.rb_node; struct rb_node * parent = NULL; struct root_info *curr; int ret; while(*p) { parent = *p; curr = rb_entry(parent, struct root_info, rb_node); ret = comp_entry_with_rootid(ins, curr, 0); if (ret < 0) p = &(*p)->rb_left; else if (ret > 0) p = &(*p)->rb_right; else return -EEXIST; } rb_link_node(&ins->rb_node, parent, p); rb_insert_color(&ins->rb_node, &root_tree->root); return 0; } /* * find a given root id in the tree. We return the smallest one, * rb_next can be used to move forward looking for more if required */ static struct root_info *root_tree_search(struct root_lookup *root_tree, u64 root_id) { struct rb_node *n = root_tree->root.rb_node; struct root_info *entry; struct root_info tmp; int ret; tmp.root_id = root_id; while(n) { entry = rb_entry(n, struct root_info, rb_node); ret = comp_entry_with_rootid(&tmp, entry, 0); if (ret < 0) n = n->rb_left; else if (ret > 0) n = n->rb_right; else return entry; } return NULL; } static int update_root(struct root_lookup *root_lookup, u64 root_id, u64 ref_tree, u64 root_offset, u64 flags, u64 dir_id, char *name, int name_len, u64 ogen, u64 gen, time_t ot, void *uuid, void *puuid, void *ruuid) { struct root_info *ri; ri = root_tree_search(root_lookup, root_id); if (!ri || ri->root_id != root_id) return -ENOENT; if (name && name_len > 0) { free(ri->name); ri->name = malloc(name_len + 1); if (!ri->name) { fprintf(stderr, "memory allocation failed\n"); exit(1); } strncpy(ri->name, name, name_len); ri->name[name_len] = 0; } if (ref_tree) ri->ref_tree = ref_tree; if (root_offset) ri->root_offset = root_offset; if (flags) ri->flags = flags; if (dir_id) ri->dir_id = dir_id; if (gen) ri->gen = gen; if (ogen) ri->ogen = ogen; if (!ri->ogen && root_offset) ri->ogen = root_offset; if (ot) ri->otime = ot; if (uuid) memcpy(&ri->uuid, uuid, BTRFS_UUID_SIZE); if (puuid) memcpy(&ri->puuid, puuid, BTRFS_UUID_SIZE); if (ruuid) memcpy(&ri->ruuid, ruuid, BTRFS_UUID_SIZE); return 0; } /* * add_root - update the existed root, or allocate a new root and insert it * into the lookup tree. * root_id: object id of the root * ref_tree: object id of the referring root. * root_offset: offset value of the root'key * dir_id: inode id of the directory in ref_tree where this root can be found. * name: the name of root_id in that directory * name_len: the length of name * ogen: the original generation of the root * gen: the current generation of the root * ot: the original time(create time) of the root * uuid: uuid of the root * puuid: uuid of the root parent if any * ruuid: uuid of the received subvol, if any */ static int add_root(struct root_lookup *root_lookup, u64 root_id, u64 ref_tree, u64 root_offset, u64 flags, u64 dir_id, char *name, int name_len, u64 ogen, u64 gen, time_t ot, void *uuid, void *puuid, void *ruuid) { struct root_info *ri; int ret; ret = update_root(root_lookup, root_id, ref_tree, root_offset, flags, dir_id, name, name_len, ogen, gen, ot, uuid, puuid, ruuid); if (!ret) return 0; ri = malloc(sizeof(*ri)); if (!ri) { printf("memory allocation failed\n"); exit(1); } memset(ri, 0, sizeof(*ri)); ri->root_id = root_id; if (name && name_len > 0) { ri->name = malloc(name_len + 1); if (!ri->name) { fprintf(stderr, "memory allocation failed\n"); exit(1); } strncpy(ri->name, name, name_len); ri->name[name_len] = 0; } if (ref_tree) ri->ref_tree = ref_tree; if (dir_id) ri->dir_id = dir_id; if (root_offset) ri->root_offset = root_offset; if (flags) ri->flags = flags; if (gen) ri->gen = gen; if (ogen) ri->ogen = ogen; if (!ri->ogen && root_offset) ri->ogen = root_offset; if (ot) ri->otime = ot; if (uuid) memcpy(&ri->uuid, uuid, BTRFS_UUID_SIZE); if (puuid) memcpy(&ri->puuid, puuid, BTRFS_UUID_SIZE); if (ruuid) memcpy(&ri->ruuid, ruuid, BTRFS_UUID_SIZE); ret = root_tree_insert(root_lookup, ri); if (ret) { printf("failed to insert tree %llu\n", (unsigned long long)root_id); exit(1); } return 0; } static void __free_root_info(struct rb_node *node) { struct root_info *ri; ri = rb_entry(node, struct root_info, rb_node); free(ri->name); free(ri->path); free(ri->full_path); free(ri); } static inline void __free_all_subvolumn(struct root_lookup *root_tree) { rb_free_nodes(&root_tree->root, __free_root_info); } /* * for a given root_info, search through the root_lookup tree to construct * the full path name to it. * * This can't be called until all the root_info->path fields are filled * in by lookup_ino_path */ static int resolve_root(struct root_lookup *rl, struct root_info *ri, u64 top_id) { char *full_path = NULL; int len = 0; struct root_info *found; /* * we go backwards from the root_info object and add pathnames * from parent directories as we go. */ found = ri; while (1) { char *tmp; u64 next; int add_len; /* * ref_tree = 0 indicates the subvolumes * has been deleted. */ if (!found->ref_tree) { free(full_path); return -ENOENT; } add_len = strlen(found->path); if (full_path) { /* room for / and for null */ tmp = malloc(add_len + 2 + len); if (!tmp) { perror("malloc failed"); exit(1); } memcpy(tmp + add_len + 1, full_path, len); tmp[add_len] = '/'; memcpy(tmp, found->path, add_len); tmp [add_len + len + 1] = '\0'; free(full_path); full_path = tmp; len += add_len + 1; } else { full_path = strdup(found->path); len = add_len; } if (!ri->top_id) ri->top_id = found->ref_tree; next = found->ref_tree; if (next == top_id) break; /* * if the ref_tree = BTRFS_FS_TREE_OBJECTID, * we are at the top */ if (next == BTRFS_FS_TREE_OBJECTID) break; /* * if the ref_tree wasn't in our tree of roots, the * subvolume was deleted. */ found = root_tree_search(rl, next); if (!found) { free(full_path); return -ENOENT; } } ri->full_path = full_path; return 0; } /* * for a single root_info, ask the kernel to give us a path name * inside it's ref_root for the dir_id where it lives. * * This fills in root_info->path with the path to the directory and and * appends this root's name. */ static int lookup_ino_path(int fd, struct root_info *ri) { struct btrfs_ioctl_ino_lookup_args args; int ret, e; if (ri->path) return 0; if (!ri->ref_tree) return -ENOENT; memset(&args, 0, sizeof(args)); args.treeid = ri->ref_tree; args.objectid = ri->dir_id; ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args); e = errno; if (ret) { if (e == ENOENT) { ri->ref_tree = 0; return -ENOENT; } fprintf(stderr, "ERROR: Failed to lookup path for root %llu - %s\n", (unsigned long long)ri->ref_tree, strerror(e)); return ret; } if (args.name[0]) { /* * we're in a subdirectory of ref_tree, the kernel ioctl * puts a / in there for us */ ri->path = malloc(strlen(ri->name) + strlen(args.name) + 1); if (!ri->path) { perror("malloc failed"); exit(1); } strcpy(ri->path, args.name); strcat(ri->path, ri->name); } else { /* we're at the root of ref_tree */ ri->path = strdup(ri->name); if (!ri->path) { perror("strdup failed"); exit(1); } } return 0; } /* finding the generation for a given path is a two step process. * First we use the inode loookup routine to find out the root id * * Then we use the tree search ioctl to scan all the root items for a * given root id and spit out the latest generation we can find */ static u64 find_root_gen(int fd) { struct btrfs_ioctl_ino_lookup_args ino_args; int ret; struct btrfs_ioctl_search_args args; struct btrfs_ioctl_search_key *sk = &args.key; struct btrfs_ioctl_search_header sh; unsigned long off = 0; u64 max_found = 0; int i; int e; memset(&ino_args, 0, sizeof(ino_args)); ino_args.objectid = BTRFS_FIRST_FREE_OBJECTID; /* this ioctl fills in ino_args->treeid */ ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &ino_args); e = errno; if (ret) { fprintf(stderr, "ERROR: Failed to lookup path for dirid %llu - %s\n", (unsigned long long)BTRFS_FIRST_FREE_OBJECTID, strerror(e)); return 0; } memset(&args, 0, sizeof(args)); sk->tree_id = 1; /* * there may be more than one ROOT_ITEM key if there are * snapshots pending deletion, we have to loop through * them. */ sk->min_objectid = ino_args.treeid; sk->max_objectid = ino_args.treeid; sk->max_type = BTRFS_ROOT_ITEM_KEY; sk->min_type = BTRFS_ROOT_ITEM_KEY; sk->max_offset = (u64)-1; sk->max_transid = (u64)-1; sk->nr_items = 4096; while (1) { ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args); e = errno; if (ret < 0) { fprintf(stderr, "ERROR: can't perform the search - %s\n", strerror(e)); return 0; } /* the ioctl returns the number of item it found in nr_items */ if (sk->nr_items == 0) break; off = 0; for (i = 0; i < sk->nr_items; i++) { struct btrfs_root_item *item; memcpy(&sh, args.buf + off, sizeof(sh)); off += sizeof(sh); item = (struct btrfs_root_item *)(args.buf + off); off += sh.len; sk->min_objectid = sh.objectid; sk->min_type = sh.type; sk->min_offset = sh.offset; if (sh.objectid > ino_args.treeid) break; if (sh.objectid == ino_args.treeid && sh.type == BTRFS_ROOT_ITEM_KEY) { max_found = max(max_found, btrfs_root_generation(item)); } } if (sk->min_offset < (u64)-1) sk->min_offset++; else break; if (sk->min_type != BTRFS_ROOT_ITEM_KEY) break; if (sk->min_objectid != ino_args.treeid) break; } return max_found; } /* pass in a directory id and this will return * the full path of the parent directory inside its * subvolume root. * * It may return NULL if it is in the root, or an ERR_PTR if things * go badly. */ static char *__ino_resolve(int fd, u64 dirid) { struct btrfs_ioctl_ino_lookup_args args; int ret; char *full; int e; memset(&args, 0, sizeof(args)); args.objectid = dirid; ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args); e = errno; if (ret) { fprintf(stderr, "ERROR: Failed to lookup path for dirid %llu - %s\n", (unsigned long long)dirid, strerror(e) ); return ERR_PTR(ret); } if (args.name[0]) { /* * we're in a subdirectory of ref_tree, the kernel ioctl * puts a / in there for us */ full = strdup(args.name); if (!full) { perror("malloc failed"); return ERR_PTR(-ENOMEM); } } else { /* we're at the root of ref_tree */ full = NULL; } return full; } /* * simple string builder, returning a new string with both * dirid and name */ static char *build_name(char *dirid, char *name) { char *full; if (!dirid) return strdup(name); full = malloc(strlen(dirid) + strlen(name) + 1); if (!full) return NULL; strcpy(full, dirid); strcat(full, name); return full; } /* * given an inode number, this returns the full path name inside the subvolume * to that file/directory. cache_dirid and cache_name are used to * cache the results so we can avoid tree searches if a later call goes * to the same directory or file name */ static char *ino_resolve(int fd, u64 ino, u64 *cache_dirid, char **cache_name) { u64 dirid; char *dirname; char *name; char *full; int ret; struct btrfs_ioctl_search_args args; struct btrfs_ioctl_search_key *sk = &args.key; struct btrfs_ioctl_search_header *sh; unsigned long off = 0; int namelen; int e; memset(&args, 0, sizeof(args)); sk->tree_id = 0; /* * step one, we search for the inode back ref. We just use the first * one */ sk->min_objectid = ino; sk->max_objectid = ino; sk->max_type = BTRFS_INODE_REF_KEY; sk->max_offset = (u64)-1; sk->min_type = BTRFS_INODE_REF_KEY; sk->max_transid = (u64)-1; sk->nr_items = 1; ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args); e = errno; if (ret < 0) { fprintf(stderr, "ERROR: can't perform the search - %s\n", strerror(e)); return NULL; } /* the ioctl returns the number of item it found in nr_items */ if (sk->nr_items == 0) return NULL; off = 0; sh = (struct btrfs_ioctl_search_header *)(args.buf + off); if (sh->type == BTRFS_INODE_REF_KEY) { struct btrfs_inode_ref *ref; dirid = sh->offset; ref = (struct btrfs_inode_ref *)(sh + 1); namelen = btrfs_stack_inode_ref_name_len(ref); name = (char *)(ref + 1); name = strndup(name, namelen); /* use our cached value */ if (dirid == *cache_dirid && *cache_name) { dirname = *cache_name; goto build; } } else { return NULL; } /* * the inode backref gives us the file name and the parent directory id. * From here we use __ino_resolve to get the path to the parent */ dirname = __ino_resolve(fd, dirid); build: full = build_name(dirname, name); if (*cache_name && dirname != *cache_name) free(*cache_name); *cache_name = dirname; *cache_dirid = dirid; free(name); return full; } int btrfs_list_get_default_subvolume(int fd, u64 *default_id) { struct btrfs_ioctl_search_args args; struct btrfs_ioctl_search_key *sk = &args.key; struct btrfs_ioctl_search_header *sh; u64 found = 0; int ret; memset(&args, 0, sizeof(args)); /* * search for a dir item with a name 'default' in the tree of * tree roots, it should point us to a default root */ sk->tree_id = 1; /* don't worry about ancient format and request only one item */ sk->nr_items = 1; sk->max_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID; sk->min_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID; sk->max_type = BTRFS_DIR_ITEM_KEY; sk->min_type = BTRFS_DIR_ITEM_KEY; sk->max_offset = (u64)-1; sk->max_transid = (u64)-1; ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args); if (ret < 0) return ret; /* the ioctl returns the number of items it found in nr_items */ if (sk->nr_items == 0) goto out; sh = (struct btrfs_ioctl_search_header *)args.buf; if (sh->type == BTRFS_DIR_ITEM_KEY) { struct btrfs_dir_item *di; int name_len; char *name; di = (struct btrfs_dir_item *)(sh + 1); name_len = btrfs_stack_dir_name_len(di); name = (char *)(di + 1); if (!strncmp("default", name, name_len)) found = btrfs_disk_key_objectid(&di->location); } out: *default_id = found; return 0; } static int __list_subvol_search(int fd, struct root_lookup *root_lookup) { int ret; struct btrfs_ioctl_search_args args; struct btrfs_ioctl_search_key *sk = &args.key; struct btrfs_ioctl_search_header sh; struct btrfs_root_ref *ref; struct btrfs_root_item *ri; unsigned long off = 0; int name_len; char *name; u64 dir_id; u64 gen = 0; u64 ogen; u64 flags; int i; time_t t; u8 uuid[BTRFS_UUID_SIZE]; u8 puuid[BTRFS_UUID_SIZE]; u8 ruuid[BTRFS_UUID_SIZE]; root_lookup_init(root_lookup); memset(&args, 0, sizeof(args)); /* search in the tree of tree roots */ sk->tree_id = 1; /* * set the min and max to backref keys. The search will * only send back this type of key now. */ sk->max_type = BTRFS_ROOT_BACKREF_KEY; sk->min_type = BTRFS_ROOT_ITEM_KEY; sk->min_objectid = BTRFS_FIRST_FREE_OBJECTID; /* * set all the other params to the max, we'll take any objectid * and any trans */ sk->max_objectid = BTRFS_LAST_FREE_OBJECTID; sk->max_offset = (u64)-1; sk->max_transid = (u64)-1; /* just a big number, doesn't matter much */ sk->nr_items = 4096; while(1) { ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args); if (ret < 0) return ret; /* the ioctl returns the number of item it found in nr_items */ if (sk->nr_items == 0) break; off = 0; /* * for each item, pull the key out of the header and then * read the root_ref item it contains */ for (i = 0; i < sk->nr_items; i++) { memcpy(&sh, args.buf + off, sizeof(sh)); off += sizeof(sh); if (sh.type == BTRFS_ROOT_BACKREF_KEY) { ref = (struct btrfs_root_ref *)(args.buf + off); name_len = btrfs_stack_root_ref_name_len(ref); name = (char *)(ref + 1); dir_id = btrfs_stack_root_ref_dirid(ref); add_root(root_lookup, sh.objectid, sh.offset, 0, 0, dir_id, name, name_len, 0, 0, 0, NULL, NULL, NULL); } else if (sh.type == BTRFS_ROOT_ITEM_KEY) { ri = (struct btrfs_root_item *)(args.buf + off); gen = btrfs_root_generation(ri); flags = btrfs_root_flags(ri); if(sh.len > sizeof(struct btrfs_root_item_v0)) { t = btrfs_stack_timespec_sec(&ri->otime); ogen = btrfs_root_otransid(ri); memcpy(uuid, ri->uuid, BTRFS_UUID_SIZE); memcpy(puuid, ri->parent_uuid, BTRFS_UUID_SIZE); memcpy(ruuid, ri->received_uuid, BTRFS_UUID_SIZE); } else { t = 0; ogen = 0; memset(uuid, 0, BTRFS_UUID_SIZE); memset(puuid, 0, BTRFS_UUID_SIZE); memset(ruuid, 0, BTRFS_UUID_SIZE); } add_root(root_lookup, sh.objectid, 0, sh.offset, flags, 0, NULL, 0, ogen, gen, t, uuid, puuid, ruuid); } off += sh.len; /* * record the mins in sk so we can make sure the * next search doesn't repeat this root */ sk->min_objectid = sh.objectid; sk->min_type = sh.type; sk->min_offset = sh.offset; } sk->nr_items = 4096; sk->min_offset++; if (!sk->min_offset) /* overflow */ sk->min_type++; else continue; if (sk->min_type > BTRFS_ROOT_BACKREF_KEY) { sk->min_type = BTRFS_ROOT_ITEM_KEY; sk->min_objectid++; } else continue; if (sk->min_objectid > sk->max_objectid) break; } return 0; } static int filter_by_rootid(struct root_info *ri, u64 data) { return ri->root_id == data; } static int filter_snapshot(struct root_info *ri, u64 data) { return !!ri->root_offset; } static int filter_flags(struct root_info *ri, u64 flags) { return ri->flags & flags; } static int filter_gen_more(struct root_info *ri, u64 data) { return ri->gen >= data; } static int filter_gen_less(struct root_info *ri, u64 data) { return ri->gen <= data; } static int filter_gen_equal(struct root_info *ri, u64 data) { return ri->gen == data; } static int filter_cgen_more(struct root_info *ri, u64 data) { return ri->ogen >= data; } static int filter_cgen_less(struct root_info *ri, u64 data) { return ri->ogen <= data; } static int filter_cgen_equal(struct root_info *ri, u64 data) { return ri->ogen == data; } static int filter_topid_equal(struct root_info *ri, u64 data) { return ri->top_id == data; } static int filter_full_path(struct root_info *ri, u64 data) { if (ri->full_path && ri->top_id != data) { char *tmp; char p[] = ""; int add_len = strlen(p); int len = strlen(ri->full_path); tmp = malloc(len + add_len + 2); if (!tmp) { fprintf(stderr, "memory allocation failed\n"); exit(1); } memcpy(tmp + add_len + 1, ri->full_path, len); tmp[len + add_len + 1] = '\0'; tmp[add_len] = '/'; memcpy(tmp, p, add_len); free(ri->full_path); ri->full_path = tmp; } return 1; } static int filter_by_parent(struct root_info *ri, u64 data) { return !uuid_compare(ri->puuid, (u8 *)(unsigned long)data); } static int filter_deleted(struct root_info *ri, u64 data) { return ri->deleted; } static btrfs_list_filter_func all_filter_funcs[] = { [BTRFS_LIST_FILTER_ROOTID] = filter_by_rootid, [BTRFS_LIST_FILTER_SNAPSHOT_ONLY] = filter_snapshot, [BTRFS_LIST_FILTER_FLAGS] = filter_flags, [BTRFS_LIST_FILTER_GEN_MORE] = filter_gen_more, [BTRFS_LIST_FILTER_GEN_LESS] = filter_gen_less, [BTRFS_LIST_FILTER_GEN_EQUAL] = filter_gen_equal, [BTRFS_LIST_FILTER_CGEN_MORE] = filter_cgen_more, [BTRFS_LIST_FILTER_CGEN_LESS] = filter_cgen_less, [BTRFS_LIST_FILTER_CGEN_EQUAL] = filter_cgen_equal, [BTRFS_LIST_FILTER_TOPID_EQUAL] = filter_topid_equal, [BTRFS_LIST_FILTER_FULL_PATH] = filter_full_path, [BTRFS_LIST_FILTER_BY_PARENT] = filter_by_parent, [BTRFS_LIST_FILTER_DELETED] = filter_deleted, }; struct btrfs_list_filter_set *btrfs_list_alloc_filter_set(void) { struct btrfs_list_filter_set *set; int size; size = sizeof(struct btrfs_list_filter_set) + BTRFS_LIST_NFILTERS_INCREASE * sizeof(struct btrfs_list_filter); set = malloc(size); if (!set) { fprintf(stderr, "memory allocation failed\n"); exit(1); } memset(set, 0, size); set->total = BTRFS_LIST_NFILTERS_INCREASE; return set; } void btrfs_list_free_filter_set(struct btrfs_list_filter_set *filter_set) { free(filter_set); } int btrfs_list_setup_filter(struct btrfs_list_filter_set **filter_set, enum btrfs_list_filter_enum filter, u64 data) { struct btrfs_list_filter_set *set = *filter_set; int size; BUG_ON(!set); BUG_ON(filter >= BTRFS_LIST_FILTER_MAX); BUG_ON(set->nfilters > set->total); if (set->nfilters == set->total) { size = set->total + BTRFS_LIST_NFILTERS_INCREASE; size = sizeof(*set) + size * sizeof(struct btrfs_list_filter); set = realloc(set, size); if (!set) { fprintf(stderr, "memory allocation failed\n"); exit(1); } memset(&set->filters[set->total], 0, BTRFS_LIST_NFILTERS_INCREASE * sizeof(struct btrfs_list_filter)); set->total += BTRFS_LIST_NFILTERS_INCREASE; *filter_set = set; } BUG_ON(set->filters[set->nfilters].filter_func); if (filter == BTRFS_LIST_FILTER_DELETED) set->only_deleted = 1; set->filters[set->nfilters].filter_func = all_filter_funcs[filter]; set->filters[set->nfilters].data = data; set->nfilters++; return 0; } static int filter_root(struct root_info *ri, struct btrfs_list_filter_set *set) { int i, ret; if (!set) return 1; if (set->only_deleted && !ri->deleted) return 0; if (!set->only_deleted && ri->deleted) return 0; for (i = 0; i < set->nfilters; i++) { if (!set->filters[i].filter_func) break; ret = set->filters[i].filter_func(ri, set->filters[i].data); if (!ret) return 0; } return 1; } static void __filter_and_sort_subvol(struct root_lookup *all_subvols, struct root_lookup *sort_tree, struct btrfs_list_filter_set *filter_set, struct btrfs_list_comparer_set *comp_set, u64 top_id) { struct rb_node *n; struct root_info *entry; int ret; root_lookup_init(sort_tree); n = rb_last(&all_subvols->root); while (n) { entry = rb_entry(n, struct root_info, rb_node); ret = resolve_root(all_subvols, entry, top_id); if (ret == -ENOENT) { entry->full_path = strdup("DELETED"); entry->deleted = 1; } ret = filter_root(entry, filter_set); if (ret) sort_tree_insert(sort_tree, entry, comp_set); n = rb_prev(n); } } static int __list_subvol_fill_paths(int fd, struct root_lookup *root_lookup) { struct rb_node *n; n = rb_first(&root_lookup->root); while (n) { struct root_info *entry; int ret; entry = rb_entry(n, struct root_info, rb_node); ret = lookup_ino_path(fd, entry); if (ret && ret != -ENOENT) return ret; n = rb_next(n); } return 0; } static void print_subvolume_column(struct root_info *subv, enum btrfs_list_column_enum column) { char tstr[256]; char uuidparse[BTRFS_UUID_UNPARSED_SIZE]; BUG_ON(column >= BTRFS_LIST_ALL || column < 0); switch (column) { case BTRFS_LIST_OBJECTID: printf("%llu", subv->root_id); break; case BTRFS_LIST_GENERATION: printf("%llu", subv->gen); break; case BTRFS_LIST_OGENERATION: printf("%llu", subv->ogen); break; case BTRFS_LIST_PARENT: printf("%llu", subv->ref_tree); break; case BTRFS_LIST_TOP_LEVEL: printf("%llu", subv->top_id); break; case BTRFS_LIST_OTIME: if (subv->otime) { struct tm tm; localtime_r(&subv->otime, &tm); strftime(tstr, 256, "%Y-%m-%d %X", &tm); } else strcpy(tstr, "-"); printf("%s", tstr); break; case BTRFS_LIST_UUID: if (uuid_is_null(subv->uuid)) strcpy(uuidparse, "-"); else uuid_unparse(subv->uuid, uuidparse); printf("%s", uuidparse); break; case BTRFS_LIST_PUUID: if (uuid_is_null(subv->puuid)) strcpy(uuidparse, "-"); else uuid_unparse(subv->puuid, uuidparse); printf("%s", uuidparse); break; case BTRFS_LIST_RUUID: if (uuid_is_null(subv->ruuid)) strcpy(uuidparse, "-"); else uuid_unparse(subv->ruuid, uuidparse); printf("%s", uuidparse); break; case BTRFS_LIST_PATH: BUG_ON(!subv->full_path); printf("%s", subv->full_path); break; default: break; } } static void print_single_volume_info_raw(struct root_info *subv, char *raw_prefix) { int i; for (i = 0; i < BTRFS_LIST_ALL; i++) { if (!btrfs_list_columns[i].need_print) continue; if (raw_prefix) printf("%s",raw_prefix); print_subvolume_column(subv, i); } printf("\n"); } static void print_single_volume_info_table(struct root_info *subv) { int i; for (i = 0; i < BTRFS_LIST_ALL; i++) { if (!btrfs_list_columns[i].need_print) continue; print_subvolume_column(subv, i); if (i != BTRFS_LIST_PATH) printf("\t"); if (i == BTRFS_LIST_TOP_LEVEL) printf("\t"); } printf("\n"); } static void print_single_volume_info_default(struct root_info *subv) { int i; for (i = 0; i < BTRFS_LIST_ALL; i++) { if (!btrfs_list_columns[i].need_print) continue; printf("%s ", btrfs_list_columns[i].name); print_subvolume_column(subv, i); if (i != BTRFS_LIST_PATH) printf(" "); } printf("\n"); } static void print_all_volume_info_tab_head(void) { int i; int len; char barrier[20]; for (i = 0; i < BTRFS_LIST_ALL; i++) { if (btrfs_list_columns[i].need_print) printf("%s\t", btrfs_list_columns[i].name); if (i == BTRFS_LIST_ALL-1) printf("\n"); } for (i = 0; i < BTRFS_LIST_ALL; i++) { memset(barrier, 0, sizeof(barrier)); if (btrfs_list_columns[i].need_print) { len = strlen(btrfs_list_columns[i].name); while (len--) strcat(barrier, "-"); printf("%s\t", barrier); } if (i == BTRFS_LIST_ALL-1) printf("\n"); } } static void print_all_volume_info(struct root_lookup *sorted_tree, int layout, char *raw_prefix) { struct rb_node *n; struct root_info *entry; if (layout == BTRFS_LIST_LAYOUT_TABLE) print_all_volume_info_tab_head(); n = rb_first(&sorted_tree->root); while (n) { entry = rb_entry(n, struct root_info, sort_node); switch (layout) { case BTRFS_LIST_LAYOUT_DEFAULT: print_single_volume_info_default(entry); break; case BTRFS_LIST_LAYOUT_TABLE: print_single_volume_info_table(entry); break; case BTRFS_LIST_LAYOUT_RAW: print_single_volume_info_raw(entry, raw_prefix); break; } n = rb_next(n); } } static int btrfs_list_subvols(int fd, struct root_lookup *root_lookup) { int ret; ret = __list_subvol_search(fd, root_lookup); if (ret) { fprintf(stderr, "ERROR: can't perform the search - %s\n", strerror(errno)); return ret; } /* * now we have an rbtree full of root_info objects, but we need to fill * in their path names within the subvol that is referencing each one. */ ret = __list_subvol_fill_paths(fd, root_lookup); return ret; } int btrfs_list_subvols_print(int fd, struct btrfs_list_filter_set *filter_set, struct btrfs_list_comparer_set *comp_set, int layout, int full_path, char *raw_prefix) { struct root_lookup root_lookup; struct root_lookup root_sort; int ret = 0; u64 top_id = 0; if (full_path) ret = btrfs_list_get_path_rootid(fd, &top_id); if (ret) return ret; ret = btrfs_list_subvols(fd, &root_lookup); if (ret) return ret; __filter_and_sort_subvol(&root_lookup, &root_sort, filter_set, comp_set, top_id); print_all_volume_info(&root_sort, layout, raw_prefix); __free_all_subvolumn(&root_lookup); return 0; } static char *strdup_or_null(const char *s) { if (!s) return NULL; return strdup(s); } int btrfs_get_subvol(int fd, struct root_info *the_ri) { int ret, rr; struct root_lookup rl; struct rb_node *rbn; struct root_info *ri; u64 root_id; ret = btrfs_list_get_path_rootid(fd, &root_id); if (ret) return ret; ret = btrfs_list_subvols(fd, &rl); if (ret) return ret; rbn = rb_first(&rl.root); while(rbn) { ri = rb_entry(rbn, struct root_info, rb_node); rr = resolve_root(&rl, ri, root_id); if (rr == -ENOENT) { ret = -ENOENT; rbn = rb_next(rbn); continue; } if (!comp_entry_with_rootid(the_ri, ri, 0)) { memcpy(the_ri, ri, offsetof(struct root_info, path)); the_ri->path = strdup_or_null(ri->path); the_ri->name = strdup_or_null(ri->name); the_ri->full_path = strdup_or_null(ri->full_path); ret = 0; break; } rbn = rb_next(rbn); } __free_all_subvolumn(&rl); return ret; } static int print_one_extent(int fd, struct btrfs_ioctl_search_header *sh, struct btrfs_file_extent_item *item, u64 found_gen, u64 *cache_dirid, char **cache_dir_name, u64 *cache_ino, char **cache_full_name) { u64 len = 0; u64 disk_start = 0; u64 disk_offset = 0; u8 type; int compressed = 0; int flags = 0; char *name = NULL; if (sh->objectid == *cache_ino) { name = *cache_full_name; } else if (*cache_full_name) { free(*cache_full_name); *cache_full_name = NULL; } if (!name) { name = ino_resolve(fd, sh->objectid, cache_dirid, cache_dir_name); *cache_full_name = name; *cache_ino = sh->objectid; } if (!name) return -EIO; type = btrfs_stack_file_extent_type(item); compressed = btrfs_stack_file_extent_compression(item); if (type == BTRFS_FILE_EXTENT_REG || type == BTRFS_FILE_EXTENT_PREALLOC) { disk_start = btrfs_stack_file_extent_disk_bytenr(item); disk_offset = btrfs_stack_file_extent_offset(item); len = btrfs_stack_file_extent_num_bytes(item); } else if (type == BTRFS_FILE_EXTENT_INLINE) { disk_start = 0; disk_offset = 0; len = btrfs_stack_file_extent_ram_bytes(item); } else { printf("unhandled extent type %d for inode %llu " "file offset %llu gen %llu\n", type, (unsigned long long)sh->objectid, (unsigned long long)sh->offset, (unsigned long long)found_gen); return -EIO; } printf("inode %llu file offset %llu len %llu disk start %llu " "offset %llu gen %llu flags ", (unsigned long long)sh->objectid, (unsigned long long)sh->offset, (unsigned long long)len, (unsigned long long)disk_start, (unsigned long long)disk_offset, (unsigned long long)found_gen); if (compressed) { printf("COMPRESS"); flags++; } if (type == BTRFS_FILE_EXTENT_PREALLOC) { printf("%sPREALLOC", flags ? "|" : ""); flags++; } if (type == BTRFS_FILE_EXTENT_INLINE) { printf("%sINLINE", flags ? "|" : ""); flags++; } if (!flags) printf("NONE"); printf(" %s\n", name); return 0; } int btrfs_list_find_updated_files(int fd, u64 root_id, u64 oldest_gen) { int ret; struct btrfs_ioctl_search_args args; struct btrfs_ioctl_search_key *sk = &args.key; struct btrfs_ioctl_search_header sh; struct btrfs_file_extent_item *item; unsigned long off = 0; u64 found_gen; u64 max_found = 0; int i; int e; u64 cache_dirid = 0; u64 cache_ino = 0; char *cache_dir_name = NULL; char *cache_full_name = NULL; struct btrfs_file_extent_item backup; memset(&backup, 0, sizeof(backup)); memset(&args, 0, sizeof(args)); sk->tree_id = root_id; /* * set all the other params to the max, we'll take any objectid * and any trans */ sk->max_objectid = (u64)-1; sk->max_offset = (u64)-1; sk->max_transid = (u64)-1; sk->max_type = BTRFS_EXTENT_DATA_KEY; sk->min_transid = oldest_gen; /* just a big number, doesn't matter much */ sk->nr_items = 4096; max_found = find_root_gen(fd); while(1) { ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args); e = errno; if (ret < 0) { fprintf(stderr, "ERROR: can't perform the search - %s\n", strerror(e)); break; } /* the ioctl returns the number of item it found in nr_items */ if (sk->nr_items == 0) break; off = 0; /* * for each item, pull the key out of the header and then * read the root_ref item it contains */ for (i = 0; i < sk->nr_items; i++) { memcpy(&sh, args.buf + off, sizeof(sh)); off += sizeof(sh); /* * just in case the item was too big, pass something other * than garbage */ if (sh.len == 0) item = &backup; else item = (struct btrfs_file_extent_item *)(args.buf + off); found_gen = btrfs_stack_file_extent_generation(item); if (sh.type == BTRFS_EXTENT_DATA_KEY && found_gen >= oldest_gen) { print_one_extent(fd, &sh, item, found_gen, &cache_dirid, &cache_dir_name, &cache_ino, &cache_full_name); } off += sh.len; /* * record the mins in sk so we can make sure the * next search doesn't repeat this root */ sk->min_objectid = sh.objectid; sk->min_offset = sh.offset; sk->min_type = sh.type; } sk->nr_items = 4096; if (sk->min_offset < (u64)-1) sk->min_offset++; else if (sk->min_objectid < (u64)-1) { sk->min_objectid++; sk->min_offset = 0; sk->min_type = 0; } else break; } free(cache_dir_name); free(cache_full_name); printf("transid marker was %llu\n", (unsigned long long)max_found); return ret; } char *btrfs_list_path_for_root(int fd, u64 root) { struct root_lookup root_lookup; struct rb_node *n; char *ret_path = NULL; int ret; u64 top_id; ret = btrfs_list_get_path_rootid(fd, &top_id); if (ret) return ERR_PTR(ret); ret = __list_subvol_search(fd, &root_lookup); if (ret < 0) return ERR_PTR(ret); ret = __list_subvol_fill_paths(fd, &root_lookup); if (ret < 0) return ERR_PTR(ret); n = rb_last(&root_lookup.root); while (n) { struct root_info *entry; entry = rb_entry(n, struct root_info, rb_node); ret = resolve_root(&root_lookup, entry, top_id); if (ret == -ENOENT && entry->root_id == root) { ret_path = NULL; break; } if (entry->root_id == root) { ret_path = entry->full_path; entry->full_path = NULL; } n = rb_prev(n); } __free_all_subvolumn(&root_lookup); return ret_path; } int btrfs_list_parse_sort_string(char *opt_arg, struct btrfs_list_comparer_set **comps) { int order; int flag; char *p; char **ptr_argv; int what_to_sort; while ((p = strtok(opt_arg, ",")) != NULL) { flag = 0; ptr_argv = all_sort_items; while (*ptr_argv) { if (strcmp(*ptr_argv, p) == 0) { flag = 1; break; } else { p++; if (strcmp(*ptr_argv, p) == 0) { flag = 1; p--; break; } p--; } ptr_argv++; } if (flag == 0) return -1; else { if (*p == '+') { order = 0; p++; } else if (*p == '-') { order = 1; p++; } else order = 0; what_to_sort = btrfs_list_get_sort_item(p); btrfs_list_setup_comparer(comps, what_to_sort, order); } opt_arg = NULL; } return 0; } /* * This function is used to parse the argument of filter condition. * * type is the filter object. */ int btrfs_list_parse_filter_string(char *opt_arg, struct btrfs_list_filter_set **filters, enum btrfs_list_filter_enum type) { u64 arg; switch (*(opt_arg++)) { case '+': arg = arg_strtou64(opt_arg); type += 2; btrfs_list_setup_filter(filters, type, arg); break; case '-': arg = arg_strtou64(opt_arg); type += 1; btrfs_list_setup_filter(filters, type, arg); break; default: opt_arg--; arg = arg_strtou64(opt_arg); btrfs_list_setup_filter(filters, type, arg); break; } return 0; } int btrfs_list_get_path_rootid(int fd, u64 *treeid) { int ret; struct btrfs_ioctl_ino_lookup_args args; memset(&args, 0, sizeof(args)); args.objectid = BTRFS_FIRST_FREE_OBJECTID; ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args); if (ret < 0) { fprintf(stderr, "ERROR: can't perform the search - %s\n", strerror(errno)); return ret; } *treeid = args.treeid; return 0; } partclone-0.2.86/src/btrfs/btrfs-list.h000066400000000000000000000107001262102574200177460ustar00rootroot00000000000000/* * Copyright (C) 2012 FUJITSU LIMITED. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. */ #if BTRFS_FLAT_INCLUDES #include "kerncompat.h" #else #include #endif /* BTRFS_FLAT_INCLUDES */ #define BTRFS_LIST_LAYOUT_DEFAULT 0 #define BTRFS_LIST_LAYOUT_TABLE 1 #define BTRFS_LIST_LAYOUT_RAW 2 /* * one of these for each root we find. */ struct root_info { struct rb_node rb_node; struct rb_node sort_node; /* this root's id */ u64 root_id; /* equal the offset of the root's key */ u64 root_offset; /* flags of the root */ u64 flags; /* the id of the root that references this one */ u64 ref_tree; /* the dir id we're in from ref_tree */ u64 dir_id; u64 top_id; /* generation when the root is created or last updated */ u64 gen; /* creation generation of this root in sec*/ u64 ogen; /* creation time of this root in sec*/ time_t otime; u8 uuid[BTRFS_UUID_SIZE]; u8 puuid[BTRFS_UUID_SIZE]; u8 ruuid[BTRFS_UUID_SIZE]; /* path from the subvol we live in to this root, including the * root's name. This is null until we do the extra lookup ioctl. */ char *path; /* the name of this root in the directory it lives in */ char *name; char *full_path; int deleted; }; typedef int (*btrfs_list_filter_func)(struct root_info *, u64); typedef int (*btrfs_list_comp_func)(struct root_info *, struct root_info *, int); struct btrfs_list_filter { btrfs_list_filter_func filter_func; u64 data; }; struct btrfs_list_comparer { btrfs_list_comp_func comp_func; int is_descending; }; struct btrfs_list_filter_set { int total; int nfilters; int only_deleted; struct btrfs_list_filter filters[0]; }; struct btrfs_list_comparer_set { int total; int ncomps; struct btrfs_list_comparer comps[0]; }; enum btrfs_list_column_enum { BTRFS_LIST_OBJECTID, BTRFS_LIST_GENERATION, BTRFS_LIST_OGENERATION, BTRFS_LIST_PARENT, BTRFS_LIST_TOP_LEVEL, BTRFS_LIST_OTIME, BTRFS_LIST_PUUID, BTRFS_LIST_RUUID, BTRFS_LIST_UUID, BTRFS_LIST_PATH, BTRFS_LIST_ALL, }; enum btrfs_list_filter_enum { BTRFS_LIST_FILTER_ROOTID, BTRFS_LIST_FILTER_SNAPSHOT_ONLY, BTRFS_LIST_FILTER_FLAGS, BTRFS_LIST_FILTER_GEN, BTRFS_LIST_FILTER_GEN_EQUAL = BTRFS_LIST_FILTER_GEN, BTRFS_LIST_FILTER_GEN_LESS, BTRFS_LIST_FILTER_GEN_MORE, BTRFS_LIST_FILTER_CGEN, BTRFS_LIST_FILTER_CGEN_EQUAL = BTRFS_LIST_FILTER_CGEN, BTRFS_LIST_FILTER_CGEN_LESS, BTRFS_LIST_FILTER_CGEN_MORE, BTRFS_LIST_FILTER_TOPID_EQUAL, BTRFS_LIST_FILTER_FULL_PATH, BTRFS_LIST_FILTER_BY_PARENT, BTRFS_LIST_FILTER_DELETED, BTRFS_LIST_FILTER_MAX, }; enum btrfs_list_comp_enum { BTRFS_LIST_COMP_ROOTID, BTRFS_LIST_COMP_OGEN, BTRFS_LIST_COMP_GEN, BTRFS_LIST_COMP_PATH, BTRFS_LIST_COMP_MAX, }; int btrfs_list_parse_sort_string(char *optarg, struct btrfs_list_comparer_set **comps); int btrfs_list_parse_filter_string(char *optarg, struct btrfs_list_filter_set **filters, enum btrfs_list_filter_enum type); void btrfs_list_setup_print_column(enum btrfs_list_column_enum column); struct btrfs_list_filter_set *btrfs_list_alloc_filter_set(void); void btrfs_list_free_filter_set(struct btrfs_list_filter_set *filter_set); int btrfs_list_setup_filter(struct btrfs_list_filter_set **filter_set, enum btrfs_list_filter_enum filter, u64 data); struct btrfs_list_comparer_set *btrfs_list_alloc_comparer_set(void); void btrfs_list_free_comparer_set(struct btrfs_list_comparer_set *comp_set); int btrfs_list_subvols_print(int fd, struct btrfs_list_filter_set *filter_set, struct btrfs_list_comparer_set *comp_set, int is_tab_result, int full_path, char *raw_prefix); int btrfs_list_find_updated_files(int fd, u64 root_id, u64 oldest_gen); int btrfs_list_get_default_subvolume(int fd, u64 *default_id); char *btrfs_list_path_for_root(int fd, u64 root); int btrfs_list_get_path_rootid(int fd, u64 *treeid); int btrfs_get_subvol(int fd, struct root_info *the_ri); partclone-0.2.86/src/btrfs/btrfsck.h000066400000000000000000000106571262102574200173260ustar00rootroot00000000000000/* * Copyright (C) 2013 FUJITSU LIMITED. All rights reserved. * Written by Miao Xie * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. */ #ifndef __CHUNK_CHECK_H__ #define __CHUNK_CHECK_H__ #if BTRFS_FLAT_INCLUDES #include "kerncompat.h" #include "extent-cache.h" #include "list.h" #else #include #include #include #endif /* BTRFS_FLAT_INCLUDES */ struct block_group_record { struct cache_extent cache; /* Used to identify the orphan block groups */ struct list_head list; u64 generation; u64 objectid; u8 type; u64 offset; u64 flags; }; struct block_group_tree { struct cache_tree tree; struct list_head block_groups; }; struct device_record { struct rb_node node; u64 devid; u64 generation; u64 objectid; u8 type; u64 offset; u64 total_byte; u64 byte_used; u64 real_used; }; struct stripe { u64 devid; u64 offset; u8 dev_uuid[BTRFS_UUID_SIZE]; }; struct chunk_record { struct cache_extent cache; struct list_head list; struct list_head dextents; struct block_group_record *bg_rec; u64 generation; u64 objectid; u8 type; u64 offset; u64 owner; u64 length; u64 type_flags; u64 stripe_len; u16 num_stripes; u16 sub_stripes; u32 io_align; u32 io_width; u32 sector_size; struct stripe stripes[0]; }; struct device_extent_record { struct cache_extent cache; /* * Used to identify the orphan device extents (the device extents * don't belong to a chunk or a device) */ struct list_head chunk_list; struct list_head device_list; u64 generation; u64 objectid; u8 type; u64 offset; u64 chunk_objecteid; u64 chunk_offset; u64 length; }; struct device_extent_tree { struct cache_tree tree; /* * The idea is: * When checking the chunk information, we move the device extents * that has its chunk to the chunk's device extents list. After the * check, if there are still some device extents in no_chunk_orphans, * it means there are some device extents which don't belong to any * chunk. * * The usage of no_device_orphans is the same as the first one, but it * is for the device information check. */ struct list_head no_chunk_orphans; struct list_head no_device_orphans; }; static inline unsigned long btrfs_chunk_record_size(int num_stripes) { return sizeof(struct chunk_record) + sizeof(struct stripe) * num_stripes; } void free_chunk_cache_tree(struct cache_tree *chunk_cache); u64 calc_stripe_length(u64 type, u64 length, int num_stripes); /* For block group tree */ static inline void block_group_tree_init(struct block_group_tree *tree) { cache_tree_init(&tree->tree); INIT_LIST_HEAD(&tree->block_groups); } int insert_block_group_record(struct block_group_tree *tree, struct block_group_record *bg_rec); void free_block_group_tree(struct block_group_tree *tree); /* For device extent tree */ static inline void device_extent_tree_init(struct device_extent_tree *tree) { cache_tree_init(&tree->tree); INIT_LIST_HEAD(&tree->no_chunk_orphans); INIT_LIST_HEAD(&tree->no_device_orphans); } int insert_device_extent_record(struct device_extent_tree *tree, struct device_extent_record *de_rec); void free_device_extent_tree(struct device_extent_tree *tree); /* Create various in-memory record by on-disk data */ struct chunk_record *btrfs_new_chunk_record(struct extent_buffer *leaf, struct btrfs_key *key, int slot); struct block_group_record * btrfs_new_block_group_record(struct extent_buffer *leaf, struct btrfs_key *key, int slot); struct device_extent_record * btrfs_new_device_extent_record(struct extent_buffer *leaf, struct btrfs_key *key, int slot); int check_chunks(struct cache_tree *chunk_cache, struct block_group_tree *block_group_cache, struct device_extent_tree *dev_extent_cache, struct list_head *good, struct list_head *bad, int silent); #endif partclone-0.2.86/src/btrfs/crc32c.c000066400000000000000000000154241262102574200167370ustar00rootroot00000000000000/* * Copied from the kernel source code, lib/libcrc32c.c. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * */ #include "kerncompat.h" #include "crc32c.h" #include #include #include #include #include #include #include u32 __crc32c_le(u32 crc, unsigned char const *data, size_t length); static u32 (*crc_function)(u32 crc, unsigned char const *data, size_t length) = __crc32c_le; #ifdef __x86_64__ /* * Based on a posting to lkml by Austin Zhang * * Using hardware provided CRC32 instruction to accelerate the CRC32 disposal. * CRC32C polynomial:0x1EDC6F41(BE)/0x82F63B78(LE) * CRC32 is a new instruction in Intel SSE4.2, the reference can be found at: * http://www.intel.com/products/processor/manuals/ * Intel(R) 64 and IA-32 Architectures Software Developer's Manual * Volume 2A: Instruction Set Reference, A-M */ #if __SIZEOF_LONG__ == 8 #define REX_PRE "0x48, " #define SCALE_F 8 #else #define REX_PRE #define SCALE_F 4 #endif static int crc32c_probed = 0; static int crc32c_intel_available = 0; static uint32_t crc32c_intel_le_hw_byte(uint32_t crc, unsigned char const *data, unsigned long length) { while (length--) { __asm__ __volatile__( ".byte 0xf2, 0xf, 0x38, 0xf0, 0xf1" :"=S"(crc) :"0"(crc), "c"(*data) ); data++; } return crc; } /* * Steps through buffer one byte at at time, calculates reflected * crc using table. */ static uint32_t crc32c_intel(u32 crc, unsigned char const *data, unsigned long length) { unsigned int iquotient = length / SCALE_F; unsigned int iremainder = length % SCALE_F; unsigned long *ptmp = (unsigned long *)data; while (iquotient--) { __asm__ __volatile__( ".byte 0xf2, " REX_PRE "0xf, 0x38, 0xf1, 0xf1;" :"=S"(crc) :"0"(crc), "c"(*ptmp) ); ptmp++; } if (iremainder) crc = crc32c_intel_le_hw_byte(crc, (unsigned char *)ptmp, iremainder); return crc; } static void do_cpuid(unsigned int *eax, unsigned int *ebx, unsigned int *ecx, unsigned int *edx) { int id = *eax; asm("movl %4, %%eax;" "cpuid;" "movl %%eax, %0;" "movl %%ebx, %1;" "movl %%ecx, %2;" "movl %%edx, %3;" : "=r" (*eax), "=r" (*ebx), "=r" (*ecx), "=r" (*edx) : "r" (id) : "eax", "ebx", "ecx", "edx"); } static void crc32c_intel_probe(void) { if (!crc32c_probed) { unsigned int eax, ebx, ecx, edx; eax = 1; do_cpuid(&eax, &ebx, &ecx, &edx); crc32c_intel_available = (ecx & (1 << 20)) != 0; crc32c_probed = 1; } } void crc32c_optimization_init(void) { crc32c_intel_probe(); if (crc32c_intel_available) crc_function = crc32c_intel; } #else void crc32c_optimization_init(void) { } #endif /* __x86_64__ */ /* * This is the CRC-32C table * Generated with: * width = 32 bits * poly = 0x1EDC6F41 * reflect input bytes = true * reflect output bytes = true */ static const u32 crc32c_table[256] = { 0x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L, 0xC79A971FL, 0x35F1141CL, 0x26A1E7E8L, 0xD4CA64EBL, 0x8AD958CFL, 0x78B2DBCCL, 0x6BE22838L, 0x9989AB3BL, 0x4D43CFD0L, 0xBF284CD3L, 0xAC78BF27L, 0x5E133C24L, 0x105EC76FL, 0xE235446CL, 0xF165B798L, 0x030E349BL, 0xD7C45070L, 0x25AFD373L, 0x36FF2087L, 0xC494A384L, 0x9A879FA0L, 0x68EC1CA3L, 0x7BBCEF57L, 0x89D76C54L, 0x5D1D08BFL, 0xAF768BBCL, 0xBC267848L, 0x4E4DFB4BL, 0x20BD8EDEL, 0xD2D60DDDL, 0xC186FE29L, 0x33ED7D2AL, 0xE72719C1L, 0x154C9AC2L, 0x061C6936L, 0xF477EA35L, 0xAA64D611L, 0x580F5512L, 0x4B5FA6E6L, 0xB93425E5L, 0x6DFE410EL, 0x9F95C20DL, 0x8CC531F9L, 0x7EAEB2FAL, 0x30E349B1L, 0xC288CAB2L, 0xD1D83946L, 0x23B3BA45L, 0xF779DEAEL, 0x05125DADL, 0x1642AE59L, 0xE4292D5AL, 0xBA3A117EL, 0x4851927DL, 0x5B016189L, 0xA96AE28AL, 0x7DA08661L, 0x8FCB0562L, 0x9C9BF696L, 0x6EF07595L, 0x417B1DBCL, 0xB3109EBFL, 0xA0406D4BL, 0x522BEE48L, 0x86E18AA3L, 0x748A09A0L, 0x67DAFA54L, 0x95B17957L, 0xCBA24573L, 0x39C9C670L, 0x2A993584L, 0xD8F2B687L, 0x0C38D26CL, 0xFE53516FL, 0xED03A29BL, 0x1F682198L, 0x5125DAD3L, 0xA34E59D0L, 0xB01EAA24L, 0x42752927L, 0x96BF4DCCL, 0x64D4CECFL, 0x77843D3BL, 0x85EFBE38L, 0xDBFC821CL, 0x2997011FL, 0x3AC7F2EBL, 0xC8AC71E8L, 0x1C661503L, 0xEE0D9600L, 0xFD5D65F4L, 0x0F36E6F7L, 0x61C69362L, 0x93AD1061L, 0x80FDE395L, 0x72966096L, 0xA65C047DL, 0x5437877EL, 0x4767748AL, 0xB50CF789L, 0xEB1FCBADL, 0x197448AEL, 0x0A24BB5AL, 0xF84F3859L, 0x2C855CB2L, 0xDEEEDFB1L, 0xCDBE2C45L, 0x3FD5AF46L, 0x7198540DL, 0x83F3D70EL, 0x90A324FAL, 0x62C8A7F9L, 0xB602C312L, 0x44694011L, 0x5739B3E5L, 0xA55230E6L, 0xFB410CC2L, 0x092A8FC1L, 0x1A7A7C35L, 0xE811FF36L, 0x3CDB9BDDL, 0xCEB018DEL, 0xDDE0EB2AL, 0x2F8B6829L, 0x82F63B78L, 0x709DB87BL, 0x63CD4B8FL, 0x91A6C88CL, 0x456CAC67L, 0xB7072F64L, 0xA457DC90L, 0x563C5F93L, 0x082F63B7L, 0xFA44E0B4L, 0xE9141340L, 0x1B7F9043L, 0xCFB5F4A8L, 0x3DDE77ABL, 0x2E8E845FL, 0xDCE5075CL, 0x92A8FC17L, 0x60C37F14L, 0x73938CE0L, 0x81F80FE3L, 0x55326B08L, 0xA759E80BL, 0xB4091BFFL, 0x466298FCL, 0x1871A4D8L, 0xEA1A27DBL, 0xF94AD42FL, 0x0B21572CL, 0xDFEB33C7L, 0x2D80B0C4L, 0x3ED04330L, 0xCCBBC033L, 0xA24BB5A6L, 0x502036A5L, 0x4370C551L, 0xB11B4652L, 0x65D122B9L, 0x97BAA1BAL, 0x84EA524EL, 0x7681D14DL, 0x2892ED69L, 0xDAF96E6AL, 0xC9A99D9EL, 0x3BC21E9DL, 0xEF087A76L, 0x1D63F975L, 0x0E330A81L, 0xFC588982L, 0xB21572C9L, 0x407EF1CAL, 0x532E023EL, 0xA145813DL, 0x758FE5D6L, 0x87E466D5L, 0x94B49521L, 0x66DF1622L, 0x38CC2A06L, 0xCAA7A905L, 0xD9F75AF1L, 0x2B9CD9F2L, 0xFF56BD19L, 0x0D3D3E1AL, 0x1E6DCDEEL, 0xEC064EEDL, 0xC38D26C4L, 0x31E6A5C7L, 0x22B65633L, 0xD0DDD530L, 0x0417B1DBL, 0xF67C32D8L, 0xE52CC12CL, 0x1747422FL, 0x49547E0BL, 0xBB3FFD08L, 0xA86F0EFCL, 0x5A048DFFL, 0x8ECEE914L, 0x7CA56A17L, 0x6FF599E3L, 0x9D9E1AE0L, 0xD3D3E1ABL, 0x21B862A8L, 0x32E8915CL, 0xC083125FL, 0x144976B4L, 0xE622F5B7L, 0xF5720643L, 0x07198540L, 0x590AB964L, 0xAB613A67L, 0xB831C993L, 0x4A5A4A90L, 0x9E902E7BL, 0x6CFBAD78L, 0x7FAB5E8CL, 0x8DC0DD8FL, 0xE330A81AL, 0x115B2B19L, 0x020BD8EDL, 0xF0605BEEL, 0x24AA3F05L, 0xD6C1BC06L, 0xC5914FF2L, 0x37FACCF1L, 0x69E9F0D5L, 0x9B8273D6L, 0x88D28022L, 0x7AB90321L, 0xAE7367CAL, 0x5C18E4C9L, 0x4F48173DL, 0xBD23943EL, 0xF36E6F75L, 0x0105EC76L, 0x12551F82L, 0xE03E9C81L, 0x34F4F86AL, 0xC69F7B69L, 0xD5CF889DL, 0x27A40B9EL, 0x79B737BAL, 0x8BDCB4B9L, 0x988C474DL, 0x6AE7C44EL, 0xBE2DA0A5L, 0x4C4623A6L, 0x5F16D052L, 0xAD7D5351L }; /* * Steps through buffer one byte at at time, calculates reflected * crc using table. */ u32 __crc32c_le(u32 crc, unsigned char const *data, size_t length) { while (length--) crc = crc32c_table[(crc ^ *data++) & 0xFFL] ^ (crc >> 8); return crc; } u32 crc32c_le(u32 crc, unsigned char const *data, size_t length) { return crc_function(crc, data, length); } partclone-0.2.86/src/btrfs/crc32c.h000066400000000000000000000021071262102574200167360ustar00rootroot00000000000000/* * Copyright (C) 2007 Red Hat. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. */ #ifndef __CRC32C__ #define __CRC32C__ #if BTRFS_FLAT_INCLUDES #include "kerncompat.h" #else #include #endif /* BTRFS_FLAT_INCLUDES */ u32 crc32c_le(u32 seed, unsigned char const *data, size_t length); void crc32c_optimization_init(void); #define crc32c(seed, data, length) crc32c_le(seed, (unsigned char const *)data, length) #define btrfs_crc32c crc32c #endif partclone-0.2.86/src/btrfs/ctree.c000066400000000000000000002241301262102574200167560ustar00rootroot00000000000000/* * Copyright (C) 2007 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. */ #include "ctree.h" #include "disk-io.h" #include "transaction.h" #include "print-tree.h" #include "repair.h" static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, int level); static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_key *ins_key, struct btrfs_path *path, int data_size, int extend); static int push_node_left(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct extent_buffer *dst, struct extent_buffer *src, int empty); static int balance_node_right(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct extent_buffer *dst_buf, struct extent_buffer *src_buf); inline void btrfs_init_path(struct btrfs_path *p) { memset(p, 0, sizeof(*p)); } struct btrfs_path *btrfs_alloc_path(void) { struct btrfs_path *path; path = kzalloc(sizeof(struct btrfs_path), GFP_NOFS); return path; } void btrfs_free_path(struct btrfs_path *p) { btrfs_release_path(p); kfree(p); } void btrfs_release_path(struct btrfs_path *p) { int i; for (i = 0; i < BTRFS_MAX_LEVEL; i++) { if (!p->nodes[i]) continue; free_extent_buffer(p->nodes[i]); } memset(p, 0, sizeof(*p)); } void add_root_to_dirty_list(struct btrfs_root *root) { if (root->track_dirty && list_empty(&root->dirty_list)) { list_add(&root->dirty_list, &root->fs_info->dirty_cowonly_roots); } } int btrfs_copy_root(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct extent_buffer *buf, struct extent_buffer **cow_ret, u64 new_root_objectid) { struct extent_buffer *cow; int ret = 0; int level; struct btrfs_root *new_root; struct btrfs_disk_key disk_key; new_root = kmalloc(sizeof(*new_root), GFP_NOFS); if (!new_root) return -ENOMEM; memcpy(new_root, root, sizeof(*new_root)); new_root->root_key.objectid = new_root_objectid; WARN_ON(root->ref_cows && trans->transid != root->fs_info->running_transaction->transid); WARN_ON(root->ref_cows && trans->transid != root->last_trans); level = btrfs_header_level(buf); if (level == 0) btrfs_item_key(buf, &disk_key, 0); else btrfs_node_key(buf, &disk_key, 0); cow = btrfs_alloc_free_block(trans, new_root, buf->len, new_root_objectid, &disk_key, level, buf->start, 0); if (IS_ERR(cow)) { kfree(new_root); return PTR_ERR(cow); } copy_extent_buffer(cow, buf, 0, 0, cow->len); btrfs_set_header_bytenr(cow, cow->start); btrfs_set_header_generation(cow, trans->transid); btrfs_set_header_backref_rev(cow, BTRFS_MIXED_BACKREF_REV); btrfs_clear_header_flag(cow, BTRFS_HEADER_FLAG_WRITTEN | BTRFS_HEADER_FLAG_RELOC); if (new_root_objectid == BTRFS_TREE_RELOC_OBJECTID) btrfs_set_header_flag(cow, BTRFS_HEADER_FLAG_RELOC); else btrfs_set_header_owner(cow, new_root_objectid); write_extent_buffer(cow, root->fs_info->fsid, btrfs_header_fsid(), BTRFS_FSID_SIZE); WARN_ON(btrfs_header_generation(buf) > trans->transid); ret = btrfs_inc_ref(trans, new_root, cow, 0); kfree(new_root); if (ret) return ret; btrfs_mark_buffer_dirty(cow); *cow_ret = cow; return 0; } /* * check if the tree block can be shared by multiple trees */ static int btrfs_block_can_be_shared(struct btrfs_root *root, struct extent_buffer *buf) { /* * Tree blocks not in refernece counted trees and tree roots * are never shared. If a block was allocated after the last * snapshot and the block was not allocated by tree relocation, * we know the block is not shared. */ if (root->ref_cows && buf != root->node && buf != root->commit_root && (btrfs_header_generation(buf) <= btrfs_root_last_snapshot(&root->root_item) || btrfs_header_flag(buf, BTRFS_HEADER_FLAG_RELOC))) return 1; #ifdef BTRFS_COMPAT_EXTENT_TREE_V0 if (root->ref_cows && btrfs_header_backref_rev(buf) < BTRFS_MIXED_BACKREF_REV) return 1; #endif return 0; } static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct extent_buffer *buf, struct extent_buffer *cow) { u64 refs; u64 owner; u64 flags; u64 new_flags = 0; int ret; /* * Backrefs update rules: * * Always use full backrefs for extent pointers in tree block * allocated by tree relocation. * * If a shared tree block is no longer referenced by its owner * tree (btrfs_header_owner(buf) == root->root_key.objectid), * use full backrefs for extent pointers in tree block. * * If a tree block is been relocating * (root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID), * use full backrefs for extent pointers in tree block. * The reason for this is some operations (such as drop tree) * are only allowed for blocks use full backrefs. */ if (btrfs_block_can_be_shared(root, buf)) { ret = btrfs_lookup_extent_info(trans, root, buf->start, btrfs_header_level(buf), 1, &refs, &flags); BUG_ON(ret); BUG_ON(refs == 0); } else { refs = 1; if (root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID || btrfs_header_backref_rev(buf) < BTRFS_MIXED_BACKREF_REV) flags = BTRFS_BLOCK_FLAG_FULL_BACKREF; else flags = 0; } owner = btrfs_header_owner(buf); BUG_ON(!(flags & BTRFS_BLOCK_FLAG_FULL_BACKREF) && owner == BTRFS_TREE_RELOC_OBJECTID); if (refs > 1) { if ((owner == root->root_key.objectid || root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID) && !(flags & BTRFS_BLOCK_FLAG_FULL_BACKREF)) { ret = btrfs_inc_ref(trans, root, buf, 1); BUG_ON(ret); if (root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID) { ret = btrfs_dec_ref(trans, root, buf, 0); BUG_ON(ret); ret = btrfs_inc_ref(trans, root, cow, 1); BUG_ON(ret); } new_flags |= BTRFS_BLOCK_FLAG_FULL_BACKREF; } else { if (root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID) ret = btrfs_inc_ref(trans, root, cow, 1); else ret = btrfs_inc_ref(trans, root, cow, 0); BUG_ON(ret); } if (new_flags != 0) { ret = btrfs_set_block_flags(trans, root, buf->start, btrfs_header_level(buf), new_flags); BUG_ON(ret); } } else { if (flags & BTRFS_BLOCK_FLAG_FULL_BACKREF) { if (root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID) ret = btrfs_inc_ref(trans, root, cow, 1); else ret = btrfs_inc_ref(trans, root, cow, 0); BUG_ON(ret); ret = btrfs_dec_ref(trans, root, buf, 1); BUG_ON(ret); } clean_tree_block(trans, root, buf); } return 0; } int __btrfs_cow_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct extent_buffer *buf, struct extent_buffer *parent, int parent_slot, struct extent_buffer **cow_ret, u64 search_start, u64 empty_size) { struct extent_buffer *cow; struct btrfs_disk_key disk_key; int level; WARN_ON(root->ref_cows && trans->transid != root->fs_info->running_transaction->transid); WARN_ON(root->ref_cows && trans->transid != root->last_trans); level = btrfs_header_level(buf); if (level == 0) btrfs_item_key(buf, &disk_key, 0); else btrfs_node_key(buf, &disk_key, 0); cow = btrfs_alloc_free_block(trans, root, buf->len, root->root_key.objectid, &disk_key, level, search_start, empty_size); if (IS_ERR(cow)) return PTR_ERR(cow); copy_extent_buffer(cow, buf, 0, 0, cow->len); btrfs_set_header_bytenr(cow, cow->start); btrfs_set_header_generation(cow, trans->transid); btrfs_set_header_backref_rev(cow, BTRFS_MIXED_BACKREF_REV); btrfs_clear_header_flag(cow, BTRFS_HEADER_FLAG_WRITTEN | BTRFS_HEADER_FLAG_RELOC); if (root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID) btrfs_set_header_flag(cow, BTRFS_HEADER_FLAG_RELOC); else btrfs_set_header_owner(cow, root->root_key.objectid); write_extent_buffer(cow, root->fs_info->fsid, btrfs_header_fsid(), BTRFS_FSID_SIZE); WARN_ON(!(buf->flags & EXTENT_BAD_TRANSID) && btrfs_header_generation(buf) > trans->transid); update_ref_for_cow(trans, root, buf, cow); if (buf == root->node) { root->node = cow; extent_buffer_get(cow); btrfs_free_extent(trans, root, buf->start, buf->len, 0, root->root_key.objectid, level, 0); free_extent_buffer(buf); add_root_to_dirty_list(root); } else { btrfs_set_node_blockptr(parent, parent_slot, cow->start); WARN_ON(trans->transid == 0); btrfs_set_node_ptr_generation(parent, parent_slot, trans->transid); btrfs_mark_buffer_dirty(parent); WARN_ON(btrfs_header_generation(parent) != trans->transid); btrfs_free_extent(trans, root, buf->start, buf->len, 0, root->root_key.objectid, level, 1); } if (!list_empty(&buf->recow)) { list_del_init(&buf->recow); free_extent_buffer(buf); } free_extent_buffer(buf); btrfs_mark_buffer_dirty(cow); *cow_ret = cow; return 0; } static inline int should_cow_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct extent_buffer *buf) { if (btrfs_header_generation(buf) == trans->transid && !btrfs_header_flag(buf, BTRFS_HEADER_FLAG_WRITTEN) && !(root->root_key.objectid != BTRFS_TREE_RELOC_OBJECTID && btrfs_header_flag(buf, BTRFS_HEADER_FLAG_RELOC))) return 0; return 1; } int btrfs_cow_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct extent_buffer *buf, struct extent_buffer *parent, int parent_slot, struct extent_buffer **cow_ret) { u64 search_start; int ret; /* if (trans->transaction != root->fs_info->running_transaction) { printk(KERN_CRIT "trans %Lu running %Lu\n", trans->transid, root->fs_info->running_transaction->transid); WARN_ON(1); } */ if (trans->transid != root->fs_info->generation) { printk(KERN_CRIT "trans %llu running %llu\n", (unsigned long long)trans->transid, (unsigned long long)root->fs_info->generation); WARN_ON(1); } if (!should_cow_block(trans, root, buf)) { *cow_ret = buf; return 0; } search_start = buf->start & ~((u64)(1024 * 1024 * 1024) - 1); ret = __btrfs_cow_block(trans, root, buf, parent, parent_slot, cow_ret, search_start, 0); return ret; } int btrfs_comp_cpu_keys(struct btrfs_key *k1, struct btrfs_key *k2) { if (k1->objectid > k2->objectid) return 1; if (k1->objectid < k2->objectid) return -1; if (k1->type > k2->type) return 1; if (k1->type < k2->type) return -1; if (k1->offset > k2->offset) return 1; if (k1->offset < k2->offset) return -1; return 0; } /* * compare two keys in a memcmp fashion */ static int btrfs_comp_keys(struct btrfs_disk_key *disk, struct btrfs_key *k2) { struct btrfs_key k1; btrfs_disk_key_to_cpu(&k1, disk); return btrfs_comp_cpu_keys(&k1, k2); } /* * The leaf data grows from end-to-front in the node. * this returns the address of the start of the last item, * which is the stop of the leaf data stack */ static inline unsigned int leaf_data_end(struct btrfs_root *root, struct extent_buffer *leaf) { u32 nr = btrfs_header_nritems(leaf); if (nr == 0) return BTRFS_LEAF_DATA_SIZE(root); return btrfs_item_offset_nr(leaf, nr - 1); } enum btrfs_tree_block_status btrfs_check_node(struct btrfs_root *root, struct btrfs_disk_key *parent_key, struct extent_buffer *buf) { int i; struct btrfs_key cpukey; struct btrfs_disk_key key; u32 nritems = btrfs_header_nritems(buf); enum btrfs_tree_block_status ret = BTRFS_TREE_BLOCK_INVALID_NRITEMS; if (nritems == 0 || nritems > BTRFS_NODEPTRS_PER_BLOCK(root)) goto fail; ret = BTRFS_TREE_BLOCK_INVALID_PARENT_KEY; if (parent_key && parent_key->type) { btrfs_node_key(buf, &key, 0); if (memcmp(parent_key, &key, sizeof(key))) goto fail; } ret = BTRFS_TREE_BLOCK_BAD_KEY_ORDER; for (i = 0; nritems > 1 && i < nritems - 2; i++) { btrfs_node_key(buf, &key, i); btrfs_node_key_to_cpu(buf, &cpukey, i + 1); if (btrfs_comp_keys(&key, &cpukey) >= 0) goto fail; } return BTRFS_TREE_BLOCK_CLEAN; fail: if (btrfs_header_owner(buf) == BTRFS_EXTENT_TREE_OBJECTID) { if (parent_key) btrfs_disk_key_to_cpu(&cpukey, parent_key); else btrfs_node_key_to_cpu(buf, &cpukey, 0); btrfs_add_corrupt_extent_record(root->fs_info, &cpukey, buf->start, buf->len, btrfs_header_level(buf)); } return ret; } enum btrfs_tree_block_status btrfs_check_leaf(struct btrfs_root *root, struct btrfs_disk_key *parent_key, struct extent_buffer *buf) { int i; struct btrfs_key cpukey; struct btrfs_disk_key key; u32 nritems = btrfs_header_nritems(buf); enum btrfs_tree_block_status ret = BTRFS_TREE_BLOCK_INVALID_NRITEMS; if (nritems * sizeof(struct btrfs_item) > buf->len) { fprintf(stderr, "invalid number of items %llu\n", (unsigned long long)buf->start); goto fail; } if (btrfs_header_level(buf) != 0) { ret = BTRFS_TREE_BLOCK_INVALID_LEVEL; fprintf(stderr, "leaf is not a leaf %llu\n", (unsigned long long)btrfs_header_bytenr(buf)); goto fail; } if (btrfs_leaf_free_space(root, buf) < 0) { ret = BTRFS_TREE_BLOCK_INVALID_FREE_SPACE; fprintf(stderr, "leaf free space incorrect %llu %d\n", (unsigned long long)btrfs_header_bytenr(buf), btrfs_leaf_free_space(root, buf)); goto fail; } if (nritems == 0) return BTRFS_TREE_BLOCK_CLEAN; btrfs_item_key(buf, &key, 0); if (parent_key && parent_key->type && memcmp(parent_key, &key, sizeof(key))) { ret = BTRFS_TREE_BLOCK_INVALID_PARENT_KEY; fprintf(stderr, "leaf parent key incorrect %llu\n", (unsigned long long)btrfs_header_bytenr(buf)); goto fail; } for (i = 0; nritems > 1 && i < nritems - 1; i++) { btrfs_item_key(buf, &key, i); btrfs_item_key_to_cpu(buf, &cpukey, i + 1); if (btrfs_comp_keys(&key, &cpukey) >= 0) { ret = BTRFS_TREE_BLOCK_BAD_KEY_ORDER; fprintf(stderr, "bad key ordering %d %d\n", i, i+1); goto fail; } if (btrfs_item_offset_nr(buf, i) != btrfs_item_end_nr(buf, i + 1)) { ret = BTRFS_TREE_BLOCK_INVALID_OFFSETS; fprintf(stderr, "incorrect offsets %u %u\n", btrfs_item_offset_nr(buf, i), btrfs_item_end_nr(buf, i + 1)); goto fail; } if (i == 0 && btrfs_item_end_nr(buf, i) != BTRFS_LEAF_DATA_SIZE(root)) { ret = BTRFS_TREE_BLOCK_INVALID_OFFSETS; fprintf(stderr, "bad item end %u wanted %u\n", btrfs_item_end_nr(buf, i), (unsigned)BTRFS_LEAF_DATA_SIZE(root)); goto fail; } } return BTRFS_TREE_BLOCK_CLEAN; fail: if (btrfs_header_owner(buf) == BTRFS_EXTENT_TREE_OBJECTID) { if (parent_key) btrfs_disk_key_to_cpu(&cpukey, parent_key); else btrfs_item_key_to_cpu(buf, &cpukey, 0); btrfs_add_corrupt_extent_record(root->fs_info, &cpukey, buf->start, buf->len, 0); } return ret; } static int noinline check_block(struct btrfs_root *root, struct btrfs_path *path, int level) { struct btrfs_disk_key key; struct btrfs_disk_key *key_ptr = NULL; struct extent_buffer *parent; enum btrfs_tree_block_status ret; if (path->skip_check_block) return 0; if (path->nodes[level + 1]) { parent = path->nodes[level + 1]; btrfs_node_key(parent, &key, path->slots[level + 1]); key_ptr = &key; } if (level == 0) ret = btrfs_check_leaf(root, key_ptr, path->nodes[0]); else ret = btrfs_check_node(root, key_ptr, path->nodes[level]); if (ret == BTRFS_TREE_BLOCK_CLEAN) return 0; return -EIO; } /* * search for key in the extent_buffer. The items start at offset p, * and they are item_size apart. There are 'max' items in p. * * the slot in the array is returned via slot, and it points to * the place where you would insert key if it is not found in * the array. * * slot may point to max if the key is bigger than all of the keys */ static int generic_bin_search(struct extent_buffer *eb, unsigned long p, int item_size, struct btrfs_key *key, int max, int *slot) { int low = 0; int high = max; int mid; int ret; unsigned long offset; struct btrfs_disk_key *tmp; while(low < high) { mid = (low + high) / 2; offset = p + mid * item_size; tmp = (struct btrfs_disk_key *)(eb->data + offset); ret = btrfs_comp_keys(tmp, key); if (ret < 0) low = mid + 1; else if (ret > 0) high = mid; else { *slot = mid; return 0; } } *slot = low; return 1; } /* * simple bin_search frontend that does the right thing for * leaves vs nodes */ static int bin_search(struct extent_buffer *eb, struct btrfs_key *key, int level, int *slot) { if (level == 0) return generic_bin_search(eb, offsetof(struct btrfs_leaf, items), sizeof(struct btrfs_item), key, btrfs_header_nritems(eb), slot); else return generic_bin_search(eb, offsetof(struct btrfs_node, ptrs), sizeof(struct btrfs_key_ptr), key, btrfs_header_nritems(eb), slot); } struct extent_buffer *read_node_slot(struct btrfs_root *root, struct extent_buffer *parent, int slot) { int level = btrfs_header_level(parent); if (slot < 0) return NULL; if (slot >= btrfs_header_nritems(parent)) return NULL; if (level == 0) return NULL; return read_tree_block(root, btrfs_node_blockptr(parent, slot), btrfs_level_size(root, level - 1), btrfs_node_ptr_generation(parent, slot)); } static int balance_level(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, int level) { struct extent_buffer *right = NULL; struct extent_buffer *mid; struct extent_buffer *left = NULL; struct extent_buffer *parent = NULL; int ret = 0; int wret; int pslot; int orig_slot = path->slots[level]; u64 orig_ptr; if (level == 0) return 0; mid = path->nodes[level]; WARN_ON(btrfs_header_generation(mid) != trans->transid); orig_ptr = btrfs_node_blockptr(mid, orig_slot); if (level < BTRFS_MAX_LEVEL - 1) { parent = path->nodes[level + 1]; pslot = path->slots[level + 1]; } /* * deal with the case where there is only one pointer in the root * by promoting the node below to a root */ if (!parent) { struct extent_buffer *child; if (btrfs_header_nritems(mid) != 1) return 0; /* promote the child to a root */ child = read_node_slot(root, mid, 0); BUG_ON(!child); ret = btrfs_cow_block(trans, root, child, mid, 0, &child); BUG_ON(ret); root->node = child; add_root_to_dirty_list(root); path->nodes[level] = NULL; clean_tree_block(trans, root, mid); wait_on_tree_block_writeback(root, mid); /* once for the path */ free_extent_buffer(mid); ret = btrfs_free_extent(trans, root, mid->start, mid->len, 0, root->root_key.objectid, level, 1); /* once for the root ptr */ free_extent_buffer(mid); return ret; } if (btrfs_header_nritems(mid) > BTRFS_NODEPTRS_PER_BLOCK(root) / 4) return 0; left = read_node_slot(root, parent, pslot - 1); if (left) { wret = btrfs_cow_block(trans, root, left, parent, pslot - 1, &left); if (wret) { ret = wret; goto enospc; } } right = read_node_slot(root, parent, pslot + 1); if (right) { wret = btrfs_cow_block(trans, root, right, parent, pslot + 1, &right); if (wret) { ret = wret; goto enospc; } } /* first, try to make some room in the middle buffer */ if (left) { orig_slot += btrfs_header_nritems(left); wret = push_node_left(trans, root, left, mid, 1); if (wret < 0) ret = wret; } /* * then try to empty the right most buffer into the middle */ if (right) { wret = push_node_left(trans, root, mid, right, 1); if (wret < 0 && wret != -ENOSPC) ret = wret; if (btrfs_header_nritems(right) == 0) { u64 bytenr = right->start; u32 blocksize = right->len; clean_tree_block(trans, root, right); wait_on_tree_block_writeback(root, right); free_extent_buffer(right); right = NULL; wret = btrfs_del_ptr(trans, root, path, level + 1, pslot + 1); if (wret) ret = wret; wret = btrfs_free_extent(trans, root, bytenr, blocksize, 0, root->root_key.objectid, level, 0); if (wret) ret = wret; } else { struct btrfs_disk_key right_key; btrfs_node_key(right, &right_key, 0); btrfs_set_node_key(parent, &right_key, pslot + 1); btrfs_mark_buffer_dirty(parent); } } if (btrfs_header_nritems(mid) == 1) { /* * we're not allowed to leave a node with one item in the * tree during a delete. A deletion from lower in the tree * could try to delete the only pointer in this node. * So, pull some keys from the left. * There has to be a left pointer at this point because * otherwise we would have pulled some pointers from the * right */ BUG_ON(!left); wret = balance_node_right(trans, root, mid, left); if (wret < 0) { ret = wret; goto enospc; } if (wret == 1) { wret = push_node_left(trans, root, left, mid, 1); if (wret < 0) ret = wret; } BUG_ON(wret == 1); } if (btrfs_header_nritems(mid) == 0) { /* we've managed to empty the middle node, drop it */ u64 bytenr = mid->start; u32 blocksize = mid->len; clean_tree_block(trans, root, mid); wait_on_tree_block_writeback(root, mid); free_extent_buffer(mid); mid = NULL; wret = btrfs_del_ptr(trans, root, path, level + 1, pslot); if (wret) ret = wret; wret = btrfs_free_extent(trans, root, bytenr, blocksize, 0, root->root_key.objectid, level, 0); if (wret) ret = wret; } else { /* update the parent key to reflect our changes */ struct btrfs_disk_key mid_key; btrfs_node_key(mid, &mid_key, 0); btrfs_set_node_key(parent, &mid_key, pslot); btrfs_mark_buffer_dirty(parent); } /* update the path */ if (left) { if (btrfs_header_nritems(left) > orig_slot) { extent_buffer_get(left); path->nodes[level] = left; path->slots[level + 1] -= 1; path->slots[level] = orig_slot; if (mid) free_extent_buffer(mid); } else { orig_slot -= btrfs_header_nritems(left); path->slots[level] = orig_slot; } } /* double check we haven't messed things up */ check_block(root, path, level); if (orig_ptr != btrfs_node_blockptr(path->nodes[level], path->slots[level])) BUG(); enospc: if (right) free_extent_buffer(right); if (left) free_extent_buffer(left); return ret; } /* returns zero if the push worked, non-zero otherwise */ static int noinline push_nodes_for_insert(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, int level) { struct extent_buffer *right = NULL; struct extent_buffer *mid; struct extent_buffer *left = NULL; struct extent_buffer *parent = NULL; int ret = 0; int wret; int pslot; int orig_slot = path->slots[level]; if (level == 0) return 1; mid = path->nodes[level]; WARN_ON(btrfs_header_generation(mid) != trans->transid); if (level < BTRFS_MAX_LEVEL - 1) { parent = path->nodes[level + 1]; pslot = path->slots[level + 1]; } if (!parent) return 1; left = read_node_slot(root, parent, pslot - 1); /* first, try to make some room in the middle buffer */ if (left) { u32 left_nr; left_nr = btrfs_header_nritems(left); if (left_nr >= BTRFS_NODEPTRS_PER_BLOCK(root) - 1) { wret = 1; } else { ret = btrfs_cow_block(trans, root, left, parent, pslot - 1, &left); if (ret) wret = 1; else { wret = push_node_left(trans, root, left, mid, 0); } } if (wret < 0) ret = wret; if (wret == 0) { struct btrfs_disk_key disk_key; orig_slot += left_nr; btrfs_node_key(mid, &disk_key, 0); btrfs_set_node_key(parent, &disk_key, pslot); btrfs_mark_buffer_dirty(parent); if (btrfs_header_nritems(left) > orig_slot) { path->nodes[level] = left; path->slots[level + 1] -= 1; path->slots[level] = orig_slot; free_extent_buffer(mid); } else { orig_slot -= btrfs_header_nritems(left); path->slots[level] = orig_slot; free_extent_buffer(left); } return 0; } free_extent_buffer(left); } right= read_node_slot(root, parent, pslot + 1); /* * then try to empty the right most buffer into the middle */ if (right) { u32 right_nr; right_nr = btrfs_header_nritems(right); if (right_nr >= BTRFS_NODEPTRS_PER_BLOCK(root) - 1) { wret = 1; } else { ret = btrfs_cow_block(trans, root, right, parent, pslot + 1, &right); if (ret) wret = 1; else { wret = balance_node_right(trans, root, right, mid); } } if (wret < 0) ret = wret; if (wret == 0) { struct btrfs_disk_key disk_key; btrfs_node_key(right, &disk_key, 0); btrfs_set_node_key(parent, &disk_key, pslot + 1); btrfs_mark_buffer_dirty(parent); if (btrfs_header_nritems(mid) <= orig_slot) { path->nodes[level] = right; path->slots[level + 1] += 1; path->slots[level] = orig_slot - btrfs_header_nritems(mid); free_extent_buffer(mid); } else { free_extent_buffer(right); } return 0; } free_extent_buffer(right); } return 1; } /* * readahead one full node of leaves */ void reada_for_search(struct btrfs_root *root, struct btrfs_path *path, int level, int slot, u64 objectid) { struct extent_buffer *node; struct btrfs_disk_key disk_key; u32 nritems; u64 search; u64 lowest_read; u64 highest_read; u64 nread = 0; int direction = path->reada; struct extent_buffer *eb; u32 nr; u32 blocksize; u32 nscan = 0; if (level != 1) return; if (!path->nodes[level]) return; node = path->nodes[level]; search = btrfs_node_blockptr(node, slot); blocksize = btrfs_level_size(root, level - 1); eb = btrfs_find_tree_block(root, search, blocksize); if (eb) { free_extent_buffer(eb); return; } highest_read = search; lowest_read = search; nritems = btrfs_header_nritems(node); nr = slot; while(1) { if (direction < 0) { if (nr == 0) break; nr--; } else if (direction > 0) { nr++; if (nr >= nritems) break; } if (path->reada < 0 && objectid) { btrfs_node_key(node, &disk_key, nr); if (btrfs_disk_key_objectid(&disk_key) != objectid) break; } search = btrfs_node_blockptr(node, nr); if ((search >= lowest_read && search <= highest_read) || (search < lowest_read && lowest_read - search <= 32768) || (search > highest_read && search - highest_read <= 32768)) { readahead_tree_block(root, search, blocksize, btrfs_node_ptr_generation(node, nr)); nread += blocksize; } nscan++; if (path->reada < 2 && (nread > (256 * 1024) || nscan > 32)) break; if(nread > (1024 * 1024) || nscan > 128) break; if (search < lowest_read) lowest_read = search; if (search > highest_read) highest_read = search; } } int btrfs_find_item(struct btrfs_root *fs_root, struct btrfs_path *found_path, u64 iobjectid, u64 ioff, u8 key_type, struct btrfs_key *found_key) { int ret; struct btrfs_key key; struct extent_buffer *eb; struct btrfs_path *path; key.type = key_type; key.objectid = iobjectid; key.offset = ioff; if (found_path == NULL) { path = btrfs_alloc_path(); if (!path) return -ENOMEM; } else path = found_path; ret = btrfs_search_slot(NULL, fs_root, &key, path, 0, 0); if ((ret < 0) || (found_key == NULL)) { if (path != found_path) btrfs_free_path(path); return ret; } eb = path->nodes[0]; if (ret && path->slots[0] >= btrfs_header_nritems(eb)) { ret = btrfs_next_leaf(fs_root, path); if (ret) return ret; eb = path->nodes[0]; } btrfs_item_key_to_cpu(eb, found_key, path->slots[0]); if (found_key->type != key.type || found_key->objectid != key.objectid) return 1; return 0; } /* * look for key in the tree. path is filled in with nodes along the way * if key is found, we return zero and you can find the item in the leaf * level of the path (level 0) * * If the key isn't found, the path points to the slot where it should * be inserted, and 1 is returned. If there are other errors during the * search a negative error number is returned. * * if ins_len > 0, nodes and leaves will be split as we walk down the * tree. if ins_len < 0, nodes will be merged as we walk down the tree (if * possible) */ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_key *key, struct btrfs_path *p, int ins_len, int cow) { struct extent_buffer *b; int slot; int ret; int level; int should_reada = p->reada; u8 lowest_level = 0; lowest_level = p->lowest_level; WARN_ON(lowest_level && ins_len > 0); WARN_ON(p->nodes[0] != NULL); /* WARN_ON(!mutex_is_locked(&root->fs_info->fs_mutex)); */ again: b = root->node; extent_buffer_get(b); while (b) { level = btrfs_header_level(b); if (cow) { int wret; wret = btrfs_cow_block(trans, root, b, p->nodes[level + 1], p->slots[level + 1], &b); if (wret) { free_extent_buffer(b); return wret; } } BUG_ON(!cow && ins_len); if (level != btrfs_header_level(b)) WARN_ON(1); level = btrfs_header_level(b); p->nodes[level] = b; ret = check_block(root, p, level); if (ret) return -1; ret = bin_search(b, key, level, &slot); if (level != 0) { if (ret && slot > 0) slot -= 1; p->slots[level] = slot; if ((p->search_for_split || ins_len > 0) && btrfs_header_nritems(b) >= BTRFS_NODEPTRS_PER_BLOCK(root) - 3) { int sret = split_node(trans, root, p, level); BUG_ON(sret > 0); if (sret) return sret; b = p->nodes[level]; slot = p->slots[level]; } else if (ins_len < 0) { int sret = balance_level(trans, root, p, level); if (sret) return sret; b = p->nodes[level]; if (!b) { btrfs_release_path(p); goto again; } slot = p->slots[level]; BUG_ON(btrfs_header_nritems(b) == 1); } /* this is only true while dropping a snapshot */ if (level == lowest_level) break; if (should_reada) reada_for_search(root, p, level, slot, key->objectid); b = read_node_slot(root, b, slot); if (!extent_buffer_uptodate(b)) return -EIO; } else { p->slots[level] = slot; if (ins_len > 0 && ins_len > btrfs_leaf_free_space(root, b)) { int sret = split_leaf(trans, root, key, p, ins_len, ret == 0); BUG_ON(sret > 0); if (sret) return sret; } return ret; } } return 1; } /* * adjust the pointers going up the tree, starting at level * making sure the right key of each node is points to 'key'. * This is used after shifting pointers to the left, so it stops * fixing up pointers when a given leaf/node is not in slot 0 of the * higher levels */ void btrfs_fixup_low_keys(struct btrfs_root *root, struct btrfs_path *path, struct btrfs_disk_key *key, int level) { int i; struct extent_buffer *t; for (i = level; i < BTRFS_MAX_LEVEL; i++) { int tslot = path->slots[i]; if (!path->nodes[i]) break; t = path->nodes[i]; btrfs_set_node_key(t, key, tslot); btrfs_mark_buffer_dirty(path->nodes[i]); if (tslot != 0) break; } } /* * update item key. * * This function isn't completely safe. It's the caller's responsibility * that the new key won't break the order */ int btrfs_set_item_key_safe(struct btrfs_root *root, struct btrfs_path *path, struct btrfs_key *new_key) { struct btrfs_disk_key disk_key; struct extent_buffer *eb; int slot; eb = path->nodes[0]; slot = path->slots[0]; if (slot > 0) { btrfs_item_key(eb, &disk_key, slot - 1); if (btrfs_comp_keys(&disk_key, new_key) >= 0) return -1; } if (slot < btrfs_header_nritems(eb) - 1) { btrfs_item_key(eb, &disk_key, slot + 1); if (btrfs_comp_keys(&disk_key, new_key) <= 0) return -1; } btrfs_cpu_key_to_disk(&disk_key, new_key); btrfs_set_item_key(eb, &disk_key, slot); btrfs_mark_buffer_dirty(eb); if (slot == 0) btrfs_fixup_low_keys(root, path, &disk_key, 1); return 0; } /* * update an item key without the safety checks. This is meant to be called by * fsck only. */ void btrfs_set_item_key_unsafe(struct btrfs_root *root, struct btrfs_path *path, struct btrfs_key *new_key) { struct btrfs_disk_key disk_key; struct extent_buffer *eb; int slot; eb = path->nodes[0]; slot = path->slots[0]; btrfs_cpu_key_to_disk(&disk_key, new_key); btrfs_set_item_key(eb, &disk_key, slot); btrfs_mark_buffer_dirty(eb); if (slot == 0) btrfs_fixup_low_keys(root, path, &disk_key, 1); } /* * try to push data from one node into the next node left in the * tree. * * returns 0 if some ptrs were pushed left, < 0 if there was some horrible * error, and > 0 if there was no room in the left hand block. */ static int push_node_left(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct extent_buffer *dst, struct extent_buffer *src, int empty) { int push_items = 0; int src_nritems; int dst_nritems; int ret = 0; src_nritems = btrfs_header_nritems(src); dst_nritems = btrfs_header_nritems(dst); push_items = BTRFS_NODEPTRS_PER_BLOCK(root) - dst_nritems; WARN_ON(btrfs_header_generation(src) != trans->transid); WARN_ON(btrfs_header_generation(dst) != trans->transid); if (!empty && src_nritems <= 8) return 1; if (push_items <= 0) { return 1; } if (empty) { push_items = min(src_nritems, push_items); if (push_items < src_nritems) { /* leave at least 8 pointers in the node if * we aren't going to empty it */ if (src_nritems - push_items < 8) { if (push_items <= 8) return 1; push_items -= 8; } } } else push_items = min(src_nritems - 8, push_items); copy_extent_buffer(dst, src, btrfs_node_key_ptr_offset(dst_nritems), btrfs_node_key_ptr_offset(0), push_items * sizeof(struct btrfs_key_ptr)); if (push_items < src_nritems) { memmove_extent_buffer(src, btrfs_node_key_ptr_offset(0), btrfs_node_key_ptr_offset(push_items), (src_nritems - push_items) * sizeof(struct btrfs_key_ptr)); } btrfs_set_header_nritems(src, src_nritems - push_items); btrfs_set_header_nritems(dst, dst_nritems + push_items); btrfs_mark_buffer_dirty(src); btrfs_mark_buffer_dirty(dst); return ret; } /* * try to push data from one node into the next node right in the * tree. * * returns 0 if some ptrs were pushed, < 0 if there was some horrible * error, and > 0 if there was no room in the right hand block. * * this will only push up to 1/2 the contents of the left node over */ static int balance_node_right(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct extent_buffer *dst, struct extent_buffer *src) { int push_items = 0; int max_push; int src_nritems; int dst_nritems; int ret = 0; WARN_ON(btrfs_header_generation(src) != trans->transid); WARN_ON(btrfs_header_generation(dst) != trans->transid); src_nritems = btrfs_header_nritems(src); dst_nritems = btrfs_header_nritems(dst); push_items = BTRFS_NODEPTRS_PER_BLOCK(root) - dst_nritems; if (push_items <= 0) { return 1; } if (src_nritems < 4) { return 1; } max_push = src_nritems / 2 + 1; /* don't try to empty the node */ if (max_push >= src_nritems) { return 1; } if (max_push < push_items) push_items = max_push; memmove_extent_buffer(dst, btrfs_node_key_ptr_offset(push_items), btrfs_node_key_ptr_offset(0), (dst_nritems) * sizeof(struct btrfs_key_ptr)); copy_extent_buffer(dst, src, btrfs_node_key_ptr_offset(0), btrfs_node_key_ptr_offset(src_nritems - push_items), push_items * sizeof(struct btrfs_key_ptr)); btrfs_set_header_nritems(src, src_nritems - push_items); btrfs_set_header_nritems(dst, dst_nritems + push_items); btrfs_mark_buffer_dirty(src); btrfs_mark_buffer_dirty(dst); return ret; } /* * helper function to insert a new root level in the tree. * A new node is allocated, and a single item is inserted to * point to the existing root * * returns zero on success or < 0 on failure. */ static int noinline insert_new_root(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, int level) { u64 lower_gen; struct extent_buffer *lower; struct extent_buffer *c; struct extent_buffer *old; struct btrfs_disk_key lower_key; BUG_ON(path->nodes[level]); BUG_ON(path->nodes[level-1] != root->node); lower = path->nodes[level-1]; if (level == 1) btrfs_item_key(lower, &lower_key, 0); else btrfs_node_key(lower, &lower_key, 0); c = btrfs_alloc_free_block(trans, root, root->nodesize, root->root_key.objectid, &lower_key, level, root->node->start, 0); if (IS_ERR(c)) return PTR_ERR(c); memset_extent_buffer(c, 0, 0, sizeof(struct btrfs_header)); btrfs_set_header_nritems(c, 1); btrfs_set_header_level(c, level); btrfs_set_header_bytenr(c, c->start); btrfs_set_header_generation(c, trans->transid); btrfs_set_header_backref_rev(c, BTRFS_MIXED_BACKREF_REV); btrfs_set_header_owner(c, root->root_key.objectid); write_extent_buffer(c, root->fs_info->fsid, btrfs_header_fsid(), BTRFS_FSID_SIZE); write_extent_buffer(c, root->fs_info->chunk_tree_uuid, btrfs_header_chunk_tree_uuid(c), BTRFS_UUID_SIZE); btrfs_set_node_key(c, &lower_key, 0); btrfs_set_node_blockptr(c, 0, lower->start); lower_gen = btrfs_header_generation(lower); WARN_ON(lower_gen != trans->transid); btrfs_set_node_ptr_generation(c, 0, lower_gen); btrfs_mark_buffer_dirty(c); old = root->node; root->node = c; /* the super has an extra ref to root->node */ free_extent_buffer(old); add_root_to_dirty_list(root); extent_buffer_get(c); path->nodes[level] = c; path->slots[level] = 0; return 0; } /* * worker function to insert a single pointer in a node. * the node should have enough room for the pointer already * * slot and level indicate where you want the key to go, and * blocknr is the block the key points to. * * returns zero on success and < 0 on any error */ static int insert_ptr(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, struct btrfs_disk_key *key, u64 bytenr, int slot, int level) { struct extent_buffer *lower; int nritems; BUG_ON(!path->nodes[level]); lower = path->nodes[level]; nritems = btrfs_header_nritems(lower); if (slot > nritems) BUG(); if (nritems == BTRFS_NODEPTRS_PER_BLOCK(root)) BUG(); if (slot != nritems) { memmove_extent_buffer(lower, btrfs_node_key_ptr_offset(slot + 1), btrfs_node_key_ptr_offset(slot), (nritems - slot) * sizeof(struct btrfs_key_ptr)); } btrfs_set_node_key(lower, key, slot); btrfs_set_node_blockptr(lower, slot, bytenr); WARN_ON(trans->transid == 0); btrfs_set_node_ptr_generation(lower, slot, trans->transid); btrfs_set_header_nritems(lower, nritems + 1); btrfs_mark_buffer_dirty(lower); return 0; } /* * split the node at the specified level in path in two. * The path is corrected to point to the appropriate node after the split * * Before splitting this tries to make some room in the node by pushing * left and right, if either one works, it returns right away. * * returns 0 on success and < 0 on failure */ static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, int level) { struct extent_buffer *c; struct extent_buffer *split; struct btrfs_disk_key disk_key; int mid; int ret; int wret; u32 c_nritems; c = path->nodes[level]; WARN_ON(btrfs_header_generation(c) != trans->transid); if (c == root->node) { /* trying to split the root, lets make a new one */ ret = insert_new_root(trans, root, path, level + 1); if (ret) return ret; } else { ret = push_nodes_for_insert(trans, root, path, level); c = path->nodes[level]; if (!ret && btrfs_header_nritems(c) < BTRFS_NODEPTRS_PER_BLOCK(root) - 3) return 0; if (ret < 0) return ret; } c_nritems = btrfs_header_nritems(c); mid = (c_nritems + 1) / 2; btrfs_node_key(c, &disk_key, mid); split = btrfs_alloc_free_block(trans, root, root->nodesize, root->root_key.objectid, &disk_key, level, c->start, 0); if (IS_ERR(split)) return PTR_ERR(split); memset_extent_buffer(split, 0, 0, sizeof(struct btrfs_header)); btrfs_set_header_level(split, btrfs_header_level(c)); btrfs_set_header_bytenr(split, split->start); btrfs_set_header_generation(split, trans->transid); btrfs_set_header_backref_rev(split, BTRFS_MIXED_BACKREF_REV); btrfs_set_header_owner(split, root->root_key.objectid); write_extent_buffer(split, root->fs_info->fsid, btrfs_header_fsid(), BTRFS_FSID_SIZE); write_extent_buffer(split, root->fs_info->chunk_tree_uuid, btrfs_header_chunk_tree_uuid(split), BTRFS_UUID_SIZE); copy_extent_buffer(split, c, btrfs_node_key_ptr_offset(0), btrfs_node_key_ptr_offset(mid), (c_nritems - mid) * sizeof(struct btrfs_key_ptr)); btrfs_set_header_nritems(split, c_nritems - mid); btrfs_set_header_nritems(c, mid); ret = 0; btrfs_mark_buffer_dirty(c); btrfs_mark_buffer_dirty(split); wret = insert_ptr(trans, root, path, &disk_key, split->start, path->slots[level + 1] + 1, level + 1); if (wret) ret = wret; if (path->slots[level] >= mid) { path->slots[level] -= mid; free_extent_buffer(c); path->nodes[level] = split; path->slots[level + 1] += 1; } else { free_extent_buffer(split); } return ret; } /* * how many bytes are required to store the items in a leaf. start * and nr indicate which items in the leaf to check. This totals up the * space used both by the item structs and the item data */ static int leaf_space_used(struct extent_buffer *l, int start, int nr) { int data_len; int nritems = btrfs_header_nritems(l); int end = min(nritems, start + nr) - 1; if (!nr) return 0; data_len = btrfs_item_end_nr(l, start); data_len = data_len - btrfs_item_offset_nr(l, end); data_len += sizeof(struct btrfs_item) * nr; WARN_ON(data_len < 0); return data_len; } /* * The space between the end of the leaf items and * the start of the leaf data. IOW, how much room * the leaf has left for both items and data */ int btrfs_leaf_free_space(struct btrfs_root *root, struct extent_buffer *leaf) { int nritems = btrfs_header_nritems(leaf); int ret; ret = BTRFS_LEAF_DATA_SIZE(root) - leaf_space_used(leaf, 0, nritems); if (ret < 0) { printk("leaf free space ret %d, leaf data size %lu, used %d nritems %d\n", ret, (unsigned long) BTRFS_LEAF_DATA_SIZE(root), leaf_space_used(leaf, 0, nritems), nritems); } return ret; } /* * push some data in the path leaf to the right, trying to free up at * least data_size bytes. returns zero if the push worked, nonzero otherwise * * returns 1 if the push failed because the other node didn't have enough * room, 0 if everything worked out and < 0 if there were major errors. */ static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, int data_size, int empty) { struct extent_buffer *left = path->nodes[0]; struct extent_buffer *right; struct extent_buffer *upper; struct btrfs_disk_key disk_key; int slot; u32 i; int free_space; int push_space = 0; int push_items = 0; struct btrfs_item *item; u32 left_nritems; u32 nr; u32 right_nritems; u32 data_end; u32 this_item_size; int ret; slot = path->slots[1]; if (!path->nodes[1]) { return 1; } upper = path->nodes[1]; if (slot >= btrfs_header_nritems(upper) - 1) return 1; right = read_node_slot(root, upper, slot + 1); free_space = btrfs_leaf_free_space(root, right); if (free_space < data_size) { free_extent_buffer(right); return 1; } /* cow and double check */ ret = btrfs_cow_block(trans, root, right, upper, slot + 1, &right); if (ret) { free_extent_buffer(right); return 1; } free_space = btrfs_leaf_free_space(root, right); if (free_space < data_size) { free_extent_buffer(right); return 1; } left_nritems = btrfs_header_nritems(left); if (left_nritems == 0) { free_extent_buffer(right); return 1; } if (empty) nr = 0; else nr = 1; i = left_nritems - 1; while (i >= nr) { item = btrfs_item_nr(i); if (path->slots[0] == i) push_space += data_size + sizeof(*item); this_item_size = btrfs_item_size(left, item); if (this_item_size + sizeof(*item) + push_space > free_space) break; push_items++; push_space += this_item_size + sizeof(*item); if (i == 0) break; i--; } if (push_items == 0) { free_extent_buffer(right); return 1; } if (!empty && push_items == left_nritems) WARN_ON(1); /* push left to right */ right_nritems = btrfs_header_nritems(right); push_space = btrfs_item_end_nr(left, left_nritems - push_items); push_space -= leaf_data_end(root, left); /* make room in the right data area */ data_end = leaf_data_end(root, right); memmove_extent_buffer(right, btrfs_leaf_data(right) + data_end - push_space, btrfs_leaf_data(right) + data_end, BTRFS_LEAF_DATA_SIZE(root) - data_end); /* copy from the left data area */ copy_extent_buffer(right, left, btrfs_leaf_data(right) + BTRFS_LEAF_DATA_SIZE(root) - push_space, btrfs_leaf_data(left) + leaf_data_end(root, left), push_space); memmove_extent_buffer(right, btrfs_item_nr_offset(push_items), btrfs_item_nr_offset(0), right_nritems * sizeof(struct btrfs_item)); /* copy the items from left to right */ copy_extent_buffer(right, left, btrfs_item_nr_offset(0), btrfs_item_nr_offset(left_nritems - push_items), push_items * sizeof(struct btrfs_item)); /* update the item pointers */ right_nritems += push_items; btrfs_set_header_nritems(right, right_nritems); push_space = BTRFS_LEAF_DATA_SIZE(root); for (i = 0; i < right_nritems; i++) { item = btrfs_item_nr(i); push_space -= btrfs_item_size(right, item); btrfs_set_item_offset(right, item, push_space); } left_nritems -= push_items; btrfs_set_header_nritems(left, left_nritems); if (left_nritems) btrfs_mark_buffer_dirty(left); btrfs_mark_buffer_dirty(right); btrfs_item_key(right, &disk_key, 0); btrfs_set_node_key(upper, &disk_key, slot + 1); btrfs_mark_buffer_dirty(upper); /* then fixup the leaf pointer in the path */ if (path->slots[0] >= left_nritems) { path->slots[0] -= left_nritems; free_extent_buffer(path->nodes[0]); path->nodes[0] = right; path->slots[1] += 1; } else { free_extent_buffer(right); } return 0; } /* * push some data in the path leaf to the left, trying to free up at * least data_size bytes. returns zero if the push worked, nonzero otherwise */ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, int data_size, int empty) { struct btrfs_disk_key disk_key; struct extent_buffer *right = path->nodes[0]; struct extent_buffer *left; int slot; int i; int free_space; int push_space = 0; int push_items = 0; struct btrfs_item *item; u32 old_left_nritems; u32 right_nritems; u32 nr; int ret = 0; u32 this_item_size; u32 old_left_item_size; slot = path->slots[1]; if (slot == 0) return 1; if (!path->nodes[1]) return 1; right_nritems = btrfs_header_nritems(right); if (right_nritems == 0) { return 1; } left = read_node_slot(root, path->nodes[1], slot - 1); free_space = btrfs_leaf_free_space(root, left); if (free_space < data_size) { free_extent_buffer(left); return 1; } /* cow and double check */ ret = btrfs_cow_block(trans, root, left, path->nodes[1], slot - 1, &left); if (ret) { /* we hit -ENOSPC, but it isn't fatal here */ free_extent_buffer(left); return 1; } free_space = btrfs_leaf_free_space(root, left); if (free_space < data_size) { free_extent_buffer(left); return 1; } if (empty) nr = right_nritems; else nr = right_nritems - 1; for (i = 0; i < nr; i++) { item = btrfs_item_nr(i); if (path->slots[0] == i) push_space += data_size + sizeof(*item); this_item_size = btrfs_item_size(right, item); if (this_item_size + sizeof(*item) + push_space > free_space) break; push_items++; push_space += this_item_size + sizeof(*item); } if (push_items == 0) { free_extent_buffer(left); return 1; } if (!empty && push_items == btrfs_header_nritems(right)) WARN_ON(1); /* push data from right to left */ copy_extent_buffer(left, right, btrfs_item_nr_offset(btrfs_header_nritems(left)), btrfs_item_nr_offset(0), push_items * sizeof(struct btrfs_item)); push_space = BTRFS_LEAF_DATA_SIZE(root) - btrfs_item_offset_nr(right, push_items -1); copy_extent_buffer(left, right, btrfs_leaf_data(left) + leaf_data_end(root, left) - push_space, btrfs_leaf_data(right) + btrfs_item_offset_nr(right, push_items - 1), push_space); old_left_nritems = btrfs_header_nritems(left); BUG_ON(old_left_nritems == 0); old_left_item_size = btrfs_item_offset_nr(left, old_left_nritems - 1); for (i = old_left_nritems; i < old_left_nritems + push_items; i++) { u32 ioff; item = btrfs_item_nr(i); ioff = btrfs_item_offset(left, item); btrfs_set_item_offset(left, item, ioff - (BTRFS_LEAF_DATA_SIZE(root) - old_left_item_size)); } btrfs_set_header_nritems(left, old_left_nritems + push_items); /* fixup right node */ if (push_items > right_nritems) { printk("push items %d nr %u\n", push_items, right_nritems); WARN_ON(1); } if (push_items < right_nritems) { push_space = btrfs_item_offset_nr(right, push_items - 1) - leaf_data_end(root, right); memmove_extent_buffer(right, btrfs_leaf_data(right) + BTRFS_LEAF_DATA_SIZE(root) - push_space, btrfs_leaf_data(right) + leaf_data_end(root, right), push_space); memmove_extent_buffer(right, btrfs_item_nr_offset(0), btrfs_item_nr_offset(push_items), (btrfs_header_nritems(right) - push_items) * sizeof(struct btrfs_item)); } right_nritems -= push_items; btrfs_set_header_nritems(right, right_nritems); push_space = BTRFS_LEAF_DATA_SIZE(root); for (i = 0; i < right_nritems; i++) { item = btrfs_item_nr(i); push_space = push_space - btrfs_item_size(right, item); btrfs_set_item_offset(right, item, push_space); } btrfs_mark_buffer_dirty(left); if (right_nritems) btrfs_mark_buffer_dirty(right); btrfs_item_key(right, &disk_key, 0); btrfs_fixup_low_keys(root, path, &disk_key, 1); /* then fixup the leaf pointer in the path */ if (path->slots[0] < push_items) { path->slots[0] += old_left_nritems; free_extent_buffer(path->nodes[0]); path->nodes[0] = left; path->slots[1] -= 1; } else { free_extent_buffer(left); path->slots[0] -= push_items; } BUG_ON(path->slots[0] < 0); return ret; } /* * split the path's leaf in two, making sure there is at least data_size * available for the resulting leaf level of the path. * * returns 0 if all went well and < 0 on failure. */ static noinline int copy_for_split(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, struct extent_buffer *l, struct extent_buffer *right, int slot, int mid, int nritems) { int data_copy_size; int rt_data_off; int i; int ret = 0; int wret; struct btrfs_disk_key disk_key; nritems = nritems - mid; btrfs_set_header_nritems(right, nritems); data_copy_size = btrfs_item_end_nr(l, mid) - leaf_data_end(root, l); copy_extent_buffer(right, l, btrfs_item_nr_offset(0), btrfs_item_nr_offset(mid), nritems * sizeof(struct btrfs_item)); copy_extent_buffer(right, l, btrfs_leaf_data(right) + BTRFS_LEAF_DATA_SIZE(root) - data_copy_size, btrfs_leaf_data(l) + leaf_data_end(root, l), data_copy_size); rt_data_off = BTRFS_LEAF_DATA_SIZE(root) - btrfs_item_end_nr(l, mid); for (i = 0; i < nritems; i++) { struct btrfs_item *item = btrfs_item_nr(i); u32 ioff = btrfs_item_offset(right, item); btrfs_set_item_offset(right, item, ioff + rt_data_off); } btrfs_set_header_nritems(l, mid); ret = 0; btrfs_item_key(right, &disk_key, 0); wret = insert_ptr(trans, root, path, &disk_key, right->start, path->slots[1] + 1, 1); if (wret) ret = wret; btrfs_mark_buffer_dirty(right); btrfs_mark_buffer_dirty(l); BUG_ON(path->slots[0] != slot); if (mid <= slot) { free_extent_buffer(path->nodes[0]); path->nodes[0] = right; path->slots[0] -= mid; path->slots[1] += 1; } else { free_extent_buffer(right); } BUG_ON(path->slots[0] < 0); return ret; } /* * split the path's leaf in two, making sure there is at least data_size * available for the resulting leaf level of the path. * * returns 0 if all went well and < 0 on failure. */ static noinline int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_key *ins_key, struct btrfs_path *path, int data_size, int extend) { struct btrfs_disk_key disk_key; struct extent_buffer *l; u32 nritems; int mid; int slot; struct extent_buffer *right; int ret = 0; int wret; int split; int num_doubles = 0; /* first try to make some room by pushing left and right */ if (data_size && ins_key->type != BTRFS_DIR_ITEM_KEY) { wret = push_leaf_right(trans, root, path, data_size, 0); if (wret < 0) return wret; if (wret) { wret = push_leaf_left(trans, root, path, data_size, 0); if (wret < 0) return wret; } l = path->nodes[0]; /* did the pushes work? */ if (btrfs_leaf_free_space(root, l) >= data_size) return 0; } if (!path->nodes[1]) { ret = insert_new_root(trans, root, path, 1); if (ret) return ret; } again: split = 1; l = path->nodes[0]; slot = path->slots[0]; nritems = btrfs_header_nritems(l); mid = (nritems + 1) / 2; if (mid <= slot) { if (nritems == 1 || leaf_space_used(l, mid, nritems - mid) + data_size > BTRFS_LEAF_DATA_SIZE(root)) { if (slot >= nritems) { split = 0; } else { mid = slot; if (mid != nritems && leaf_space_used(l, mid, nritems - mid) + data_size > BTRFS_LEAF_DATA_SIZE(root)) { split = 2; } } } } else { if (leaf_space_used(l, 0, mid) + data_size > BTRFS_LEAF_DATA_SIZE(root)) { if (!extend && data_size && slot == 0) { split = 0; } else if ((extend || !data_size) && slot == 0) { mid = 1; } else { mid = slot; if (mid != nritems && leaf_space_used(l, mid, nritems - mid) + data_size > BTRFS_LEAF_DATA_SIZE(root)) { split = 2 ; } } } } if (split == 0) btrfs_cpu_key_to_disk(&disk_key, ins_key); else btrfs_item_key(l, &disk_key, mid); right = btrfs_alloc_free_block(trans, root, root->leafsize, root->root_key.objectid, &disk_key, 0, l->start, 0); if (IS_ERR(right)) { BUG_ON(1); return PTR_ERR(right); } memset_extent_buffer(right, 0, 0, sizeof(struct btrfs_header)); btrfs_set_header_bytenr(right, right->start); btrfs_set_header_generation(right, trans->transid); btrfs_set_header_backref_rev(right, BTRFS_MIXED_BACKREF_REV); btrfs_set_header_owner(right, root->root_key.objectid); btrfs_set_header_level(right, 0); write_extent_buffer(right, root->fs_info->fsid, btrfs_header_fsid(), BTRFS_FSID_SIZE); write_extent_buffer(right, root->fs_info->chunk_tree_uuid, btrfs_header_chunk_tree_uuid(right), BTRFS_UUID_SIZE); if (split == 0) { if (mid <= slot) { btrfs_set_header_nritems(right, 0); wret = insert_ptr(trans, root, path, &disk_key, right->start, path->slots[1] + 1, 1); if (wret) ret = wret; free_extent_buffer(path->nodes[0]); path->nodes[0] = right; path->slots[0] = 0; path->slots[1] += 1; } else { btrfs_set_header_nritems(right, 0); wret = insert_ptr(trans, root, path, &disk_key, right->start, path->slots[1], 1); if (wret) ret = wret; free_extent_buffer(path->nodes[0]); path->nodes[0] = right; path->slots[0] = 0; if (path->slots[1] == 0) { btrfs_fixup_low_keys(root, path, &disk_key, 1); } } btrfs_mark_buffer_dirty(right); return ret; } ret = copy_for_split(trans, root, path, l, right, slot, mid, nritems); BUG_ON(ret); if (split == 2) { BUG_ON(num_doubles != 0); num_doubles++; goto again; } return ret; } /* * This function splits a single item into two items, * giving 'new_key' to the new item and splitting the * old one at split_offset (from the start of the item). * * The path may be released by this operation. After * the split, the path is pointing to the old item. The * new item is going to be in the same node as the old one. * * Note, the item being split must be smaller enough to live alone on * a tree block with room for one extra struct btrfs_item * * This allows us to split the item in place, keeping a lock on the * leaf the entire time. */ int btrfs_split_item(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, struct btrfs_key *new_key, unsigned long split_offset) { u32 item_size; struct extent_buffer *leaf; struct btrfs_key orig_key; struct btrfs_item *item; struct btrfs_item *new_item; int ret = 0; int slot; u32 nritems; u32 orig_offset; struct btrfs_disk_key disk_key; char *buf; leaf = path->nodes[0]; btrfs_item_key_to_cpu(leaf, &orig_key, path->slots[0]); if (btrfs_leaf_free_space(root, leaf) >= sizeof(struct btrfs_item)) goto split; item_size = btrfs_item_size_nr(leaf, path->slots[0]); btrfs_release_path(path); path->search_for_split = 1; ret = btrfs_search_slot(trans, root, &orig_key, path, 0, 1); path->search_for_split = 0; /* if our item isn't there or got smaller, return now */ if (ret != 0 || item_size != btrfs_item_size_nr(path->nodes[0], path->slots[0])) { return -EAGAIN; } ret = split_leaf(trans, root, &orig_key, path, 0, 0); BUG_ON(ret); BUG_ON(btrfs_leaf_free_space(root, leaf) < sizeof(struct btrfs_item)); leaf = path->nodes[0]; split: item = btrfs_item_nr(path->slots[0]); orig_offset = btrfs_item_offset(leaf, item); item_size = btrfs_item_size(leaf, item); buf = kmalloc(item_size, GFP_NOFS); read_extent_buffer(leaf, buf, btrfs_item_ptr_offset(leaf, path->slots[0]), item_size); slot = path->slots[0] + 1; leaf = path->nodes[0]; nritems = btrfs_header_nritems(leaf); if (slot != nritems) { /* shift the items */ memmove_extent_buffer(leaf, btrfs_item_nr_offset(slot + 1), btrfs_item_nr_offset(slot), (nritems - slot) * sizeof(struct btrfs_item)); } btrfs_cpu_key_to_disk(&disk_key, new_key); btrfs_set_item_key(leaf, &disk_key, slot); new_item = btrfs_item_nr(slot); btrfs_set_item_offset(leaf, new_item, orig_offset); btrfs_set_item_size(leaf, new_item, item_size - split_offset); btrfs_set_item_offset(leaf, item, orig_offset + item_size - split_offset); btrfs_set_item_size(leaf, item, split_offset); btrfs_set_header_nritems(leaf, nritems + 1); /* write the data for the start of the original item */ write_extent_buffer(leaf, buf, btrfs_item_ptr_offset(leaf, path->slots[0]), split_offset); /* write the data for the new item */ write_extent_buffer(leaf, buf + split_offset, btrfs_item_ptr_offset(leaf, slot), item_size - split_offset); btrfs_mark_buffer_dirty(leaf); ret = 0; if (btrfs_leaf_free_space(root, leaf) < 0) { btrfs_print_leaf(root, leaf); BUG(); } kfree(buf); return ret; } int btrfs_truncate_item(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, u32 new_size, int from_end) { int ret = 0; int slot; struct extent_buffer *leaf; struct btrfs_item *item; u32 nritems; unsigned int data_end; unsigned int old_data_start; unsigned int old_size; unsigned int size_diff; int i; leaf = path->nodes[0]; slot = path->slots[0]; old_size = btrfs_item_size_nr(leaf, slot); if (old_size == new_size) return 0; nritems = btrfs_header_nritems(leaf); data_end = leaf_data_end(root, leaf); old_data_start = btrfs_item_offset_nr(leaf, slot); size_diff = old_size - new_size; BUG_ON(slot < 0); BUG_ON(slot >= nritems); /* * item0..itemN ... dataN.offset..dataN.size .. data0.size */ /* first correct the data pointers */ for (i = slot; i < nritems; i++) { u32 ioff; item = btrfs_item_nr(i); ioff = btrfs_item_offset(leaf, item); btrfs_set_item_offset(leaf, item, ioff + size_diff); } /* shift the data */ if (from_end) { memmove_extent_buffer(leaf, btrfs_leaf_data(leaf) + data_end + size_diff, btrfs_leaf_data(leaf) + data_end, old_data_start + new_size - data_end); } else { struct btrfs_disk_key disk_key; u64 offset; btrfs_item_key(leaf, &disk_key, slot); if (btrfs_disk_key_type(&disk_key) == BTRFS_EXTENT_DATA_KEY) { unsigned long ptr; struct btrfs_file_extent_item *fi; fi = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item); fi = (struct btrfs_file_extent_item *)( (unsigned long)fi - size_diff); if (btrfs_file_extent_type(leaf, fi) == BTRFS_FILE_EXTENT_INLINE) { ptr = btrfs_item_ptr_offset(leaf, slot); memmove_extent_buffer(leaf, ptr, (unsigned long)fi, offsetof(struct btrfs_file_extent_item, disk_bytenr)); } } memmove_extent_buffer(leaf, btrfs_leaf_data(leaf) + data_end + size_diff, btrfs_leaf_data(leaf) + data_end, old_data_start - data_end); offset = btrfs_disk_key_offset(&disk_key); btrfs_set_disk_key_offset(&disk_key, offset + size_diff); btrfs_set_item_key(leaf, &disk_key, slot); if (slot == 0) btrfs_fixup_low_keys(root, path, &disk_key, 1); } item = btrfs_item_nr(slot); btrfs_set_item_size(leaf, item, new_size); btrfs_mark_buffer_dirty(leaf); ret = 0; if (btrfs_leaf_free_space(root, leaf) < 0) { btrfs_print_leaf(root, leaf); BUG(); } return ret; } int btrfs_extend_item(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, u32 data_size) { int ret = 0; int slot; struct extent_buffer *leaf; struct btrfs_item *item; u32 nritems; unsigned int data_end; unsigned int old_data; unsigned int old_size; int i; leaf = path->nodes[0]; nritems = btrfs_header_nritems(leaf); data_end = leaf_data_end(root, leaf); if (btrfs_leaf_free_space(root, leaf) < data_size) { btrfs_print_leaf(root, leaf); BUG(); } slot = path->slots[0]; old_data = btrfs_item_end_nr(leaf, slot); BUG_ON(slot < 0); if (slot >= nritems) { btrfs_print_leaf(root, leaf); printk("slot %d too large, nritems %d\n", slot, nritems); BUG_ON(1); } /* * item0..itemN ... dataN.offset..dataN.size .. data0.size */ /* first correct the data pointers */ for (i = slot; i < nritems; i++) { u32 ioff; item = btrfs_item_nr(i); ioff = btrfs_item_offset(leaf, item); btrfs_set_item_offset(leaf, item, ioff - data_size); } /* shift the data */ memmove_extent_buffer(leaf, btrfs_leaf_data(leaf) + data_end - data_size, btrfs_leaf_data(leaf) + data_end, old_data - data_end); data_end = old_data; old_size = btrfs_item_size_nr(leaf, slot); item = btrfs_item_nr(slot); btrfs_set_item_size(leaf, item, old_size + data_size); btrfs_mark_buffer_dirty(leaf); ret = 0; if (btrfs_leaf_free_space(root, leaf) < 0) { btrfs_print_leaf(root, leaf); BUG(); } return ret; } /* * Given a key and some data, insert an item into the tree. * This does all the path init required, making room in the tree if needed. */ int btrfs_insert_empty_items(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, struct btrfs_key *cpu_key, u32 *data_size, int nr) { struct extent_buffer *leaf; struct btrfs_item *item; int ret = 0; int slot; int i; u32 nritems; u32 total_size = 0; u32 total_data = 0; unsigned int data_end; struct btrfs_disk_key disk_key; for (i = 0; i < nr; i++) { total_data += data_size[i]; } /* create a root if there isn't one */ if (!root->node) BUG(); total_size = total_data + nr * sizeof(struct btrfs_item); ret = btrfs_search_slot(trans, root, cpu_key, path, total_size, 1); if (ret == 0) { return -EEXIST; } if (ret < 0) goto out; leaf = path->nodes[0]; nritems = btrfs_header_nritems(leaf); data_end = leaf_data_end(root, leaf); if (btrfs_leaf_free_space(root, leaf) < total_size) { btrfs_print_leaf(root, leaf); printk("not enough freespace need %u have %d\n", total_size, btrfs_leaf_free_space(root, leaf)); BUG(); } slot = path->slots[0]; BUG_ON(slot < 0); if (slot != nritems) { unsigned int old_data = btrfs_item_end_nr(leaf, slot); if (old_data < data_end) { btrfs_print_leaf(root, leaf); printk("slot %d old_data %d data_end %d\n", slot, old_data, data_end); BUG_ON(1); } /* * item0..itemN ... dataN.offset..dataN.size .. data0.size */ /* first correct the data pointers */ for (i = slot; i < nritems; i++) { u32 ioff; item = btrfs_item_nr(i); ioff = btrfs_item_offset(leaf, item); btrfs_set_item_offset(leaf, item, ioff - total_data); } /* shift the items */ memmove_extent_buffer(leaf, btrfs_item_nr_offset(slot + nr), btrfs_item_nr_offset(slot), (nritems - slot) * sizeof(struct btrfs_item)); /* shift the data */ memmove_extent_buffer(leaf, btrfs_leaf_data(leaf) + data_end - total_data, btrfs_leaf_data(leaf) + data_end, old_data - data_end); data_end = old_data; } /* setup the item for the new data */ for (i = 0; i < nr; i++) { btrfs_cpu_key_to_disk(&disk_key, cpu_key + i); btrfs_set_item_key(leaf, &disk_key, slot + i); item = btrfs_item_nr(slot + i); btrfs_set_item_offset(leaf, item, data_end - data_size[i]); data_end -= data_size[i]; btrfs_set_item_size(leaf, item, data_size[i]); } btrfs_set_header_nritems(leaf, nritems + nr); btrfs_mark_buffer_dirty(leaf); ret = 0; if (slot == 0) { btrfs_cpu_key_to_disk(&disk_key, cpu_key); btrfs_fixup_low_keys(root, path, &disk_key, 1); } if (btrfs_leaf_free_space(root, leaf) < 0) { btrfs_print_leaf(root, leaf); BUG(); } out: return ret; } /* * Given a key and some data, insert an item into the tree. * This does all the path init required, making room in the tree if needed. */ int btrfs_insert_item(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_key *cpu_key, void *data, u32 data_size) { int ret = 0; struct btrfs_path *path; struct extent_buffer *leaf; unsigned long ptr; path = btrfs_alloc_path(); BUG_ON(!path); ret = btrfs_insert_empty_item(trans, root, path, cpu_key, data_size); if (!ret) { leaf = path->nodes[0]; ptr = btrfs_item_ptr_offset(leaf, path->slots[0]); write_extent_buffer(leaf, data, ptr, data_size); btrfs_mark_buffer_dirty(leaf); } btrfs_free_path(path); return ret; } /* * delete the pointer from a given node. * * If the delete empties a node, the node is removed from the tree, * continuing all the way the root if required. The root is converted into * a leaf if all the nodes are emptied. */ int btrfs_del_ptr(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, int level, int slot) { struct extent_buffer *parent = path->nodes[level]; u32 nritems; int ret = 0; nritems = btrfs_header_nritems(parent); if (slot != nritems -1) { memmove_extent_buffer(parent, btrfs_node_key_ptr_offset(slot), btrfs_node_key_ptr_offset(slot + 1), sizeof(struct btrfs_key_ptr) * (nritems - slot - 1)); } nritems--; btrfs_set_header_nritems(parent, nritems); if (nritems == 0 && parent == root->node) { BUG_ON(btrfs_header_level(root->node) != 1); /* just turn the root into a leaf and break */ btrfs_set_header_level(root->node, 0); } else if (slot == 0) { struct btrfs_disk_key disk_key; btrfs_node_key(parent, &disk_key, 0); btrfs_fixup_low_keys(root, path, &disk_key, level + 1); } btrfs_mark_buffer_dirty(parent); return ret; } /* * a helper function to delete the leaf pointed to by path->slots[1] and * path->nodes[1]. * * This deletes the pointer in path->nodes[1] and frees the leaf * block extent. zero is returned if it all worked out, < 0 otherwise. * * The path must have already been setup for deleting the leaf, including * all the proper balancing. path->nodes[1] must be locked. */ static noinline int btrfs_del_leaf(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, struct extent_buffer *leaf) { int ret; WARN_ON(btrfs_header_generation(leaf) != trans->transid); ret = btrfs_del_ptr(trans, root, path, 1, path->slots[1]); if (ret) return ret; ret = btrfs_free_extent(trans, root, leaf->start, leaf->len, 0, root->root_key.objectid, 0, 0); return ret; } /* * delete the item at the leaf level in path. If that empties * the leaf, remove it from the tree */ int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, int slot, int nr) { struct extent_buffer *leaf; struct btrfs_item *item; int last_off; int dsize = 0; int ret = 0; int wret; int i; u32 nritems; leaf = path->nodes[0]; last_off = btrfs_item_offset_nr(leaf, slot + nr - 1); for (i = 0; i < nr; i++) dsize += btrfs_item_size_nr(leaf, slot + i); nritems = btrfs_header_nritems(leaf); if (slot + nr != nritems) { int data_end = leaf_data_end(root, leaf); memmove_extent_buffer(leaf, btrfs_leaf_data(leaf) + data_end + dsize, btrfs_leaf_data(leaf) + data_end, last_off - data_end); for (i = slot + nr; i < nritems; i++) { u32 ioff; item = btrfs_item_nr(i); ioff = btrfs_item_offset(leaf, item); btrfs_set_item_offset(leaf, item, ioff + dsize); } memmove_extent_buffer(leaf, btrfs_item_nr_offset(slot), btrfs_item_nr_offset(slot + nr), sizeof(struct btrfs_item) * (nritems - slot - nr)); } btrfs_set_header_nritems(leaf, nritems - nr); nritems -= nr; /* delete the leaf if we've emptied it */ if (nritems == 0) { if (leaf == root->node) { btrfs_set_header_level(leaf, 0); } else { clean_tree_block(trans, root, leaf); wait_on_tree_block_writeback(root, leaf); wret = btrfs_del_leaf(trans, root, path, leaf); BUG_ON(ret); if (wret) ret = wret; } } else { int used = leaf_space_used(leaf, 0, nritems); if (slot == 0) { struct btrfs_disk_key disk_key; btrfs_item_key(leaf, &disk_key, 0); btrfs_fixup_low_keys(root, path, &disk_key, 1); } /* delete the leaf if it is mostly empty */ if (used < BTRFS_LEAF_DATA_SIZE(root) / 4) { /* push_leaf_left fixes the path. * make sure the path still points to our leaf * for possible call to del_ptr below */ slot = path->slots[1]; extent_buffer_get(leaf); wret = push_leaf_left(trans, root, path, 1, 1); if (wret < 0 && wret != -ENOSPC) ret = wret; if (path->nodes[0] == leaf && btrfs_header_nritems(leaf)) { wret = push_leaf_right(trans, root, path, 1, 1); if (wret < 0 && wret != -ENOSPC) ret = wret; } if (btrfs_header_nritems(leaf) == 0) { clean_tree_block(trans, root, leaf); wait_on_tree_block_writeback(root, leaf); path->slots[1] = slot; ret = btrfs_del_leaf(trans, root, path, leaf); BUG_ON(ret); free_extent_buffer(leaf); } else { btrfs_mark_buffer_dirty(leaf); free_extent_buffer(leaf); } } else { btrfs_mark_buffer_dirty(leaf); } } return ret; } /* * walk up the tree as far as required to find the previous leaf. * returns 0 if it found something or 1 if there are no lesser leaves. * returns < 0 on io errors. */ int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path) { int slot; int level = 1; struct extent_buffer *c; struct extent_buffer *next = NULL; while(level < BTRFS_MAX_LEVEL) { if (!path->nodes[level]) return 1; slot = path->slots[level]; c = path->nodes[level]; if (slot == 0) { level++; if (level == BTRFS_MAX_LEVEL) return 1; continue; } slot--; next = read_node_slot(root, c, slot); break; } path->slots[level] = slot; while(1) { level--; c = path->nodes[level]; free_extent_buffer(c); slot = btrfs_header_nritems(next); if (slot != 0) slot--; path->nodes[level] = next; path->slots[level] = slot; if (!level) break; next = read_node_slot(root, next, slot); } return 0; } /* * walk up the tree as far as required to find the next leaf. * returns 0 if it found something or 1 if there are no greater leaves. * returns < 0 on io errors. */ int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path) { int slot; int level = 1; struct extent_buffer *c; struct extent_buffer *next = NULL; while(level < BTRFS_MAX_LEVEL) { if (!path->nodes[level]) return 1; slot = path->slots[level] + 1; c = path->nodes[level]; if (slot >= btrfs_header_nritems(c)) { level++; if (level == BTRFS_MAX_LEVEL) return 1; continue; } if (path->reada) reada_for_search(root, path, level, slot, 0); next = read_node_slot(root, c, slot); if (!next) return -EIO; break; } path->slots[level] = slot; while(1) { level--; c = path->nodes[level]; free_extent_buffer(c); path->nodes[level] = next; path->slots[level] = 0; if (!level) break; if (path->reada) reada_for_search(root, path, level, 0, 0); next = read_node_slot(root, next, 0); if (!next) return -EIO; } return 0; } int btrfs_previous_item(struct btrfs_root *root, struct btrfs_path *path, u64 min_objectid, int type) { struct btrfs_key found_key; struct extent_buffer *leaf; int ret; while(1) { if (path->slots[0] == 0) { ret = btrfs_prev_leaf(root, path); if (ret != 0) return ret; } else { path->slots[0]--; } leaf = path->nodes[0]; btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); if (found_key.type == type) return 0; } return 1; } /* * search in extent tree to find a previous Metadata/Data extent item with * min objecitd. * * returns 0 if something is found, 1 if nothing was found and < 0 on error */ int btrfs_previous_extent_item(struct btrfs_root *root, struct btrfs_path *path, u64 min_objectid) { struct btrfs_key found_key; struct extent_buffer *leaf; u32 nritems; int ret; while (1) { if (path->slots[0] == 0) { ret = btrfs_prev_leaf(root, path); if (ret != 0) return ret; } else { path->slots[0]--; } leaf = path->nodes[0]; nritems = btrfs_header_nritems(leaf); if (nritems == 0) return 1; if (path->slots[0] == nritems) path->slots[0]--; btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); if (found_key.objectid < min_objectid) break; if (found_key.type == BTRFS_EXTENT_ITEM_KEY || found_key.type == BTRFS_METADATA_ITEM_KEY) return 0; if (found_key.objectid == min_objectid && found_key.type < BTRFS_EXTENT_ITEM_KEY) break; } return 1; } partclone-0.2.86/src/btrfs/ctree.h000066400000000000000000002327251262102574200167740ustar00rootroot00000000000000/* * Copyright (C) 2007 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. */ #ifndef __BTRFS__ #define __BTRFS__ #if BTRFS_FLAT_INCLUDES #include "list.h" #include "kerncompat.h" #include "radix-tree.h" #include "extent-cache.h" #include "extent_io.h" #include "ioctl.h" #else #include #include #include #include #include #include #endif /* BTRFS_FLAT_INCLUDES */ struct btrfs_root; struct btrfs_trans_handle; struct btrfs_free_space_ctl; #define BTRFS_MAGIC 0x4D5F53665248425FULL /* ascii _BHRfS_M, no null */ #define BTRFS_MAX_MIRRORS 3 #define BTRFS_MAX_LEVEL 8 #define BTRFS_COMPAT_EXTENT_TREE_V0 /* holds pointers to all of the tree roots */ #define BTRFS_ROOT_TREE_OBJECTID 1ULL /* stores information about which extents are in use, and reference counts */ #define BTRFS_EXTENT_TREE_OBJECTID 2ULL /* * chunk tree stores translations from logical -> physical block numbering * the super block points to the chunk tree */ #define BTRFS_CHUNK_TREE_OBJECTID 3ULL /* * stores information about which areas of a given device are in use. * one per device. The tree of tree roots points to the device tree */ #define BTRFS_DEV_TREE_OBJECTID 4ULL /* one per subvolume, storing files and directories */ #define BTRFS_FS_TREE_OBJECTID 5ULL /* directory objectid inside the root tree */ #define BTRFS_ROOT_TREE_DIR_OBJECTID 6ULL /* holds checksums of all the data extents */ #define BTRFS_CSUM_TREE_OBJECTID 7ULL #define BTRFS_QUOTA_TREE_OBJECTID 8ULL /* for storing items that use the BTRFS_UUID_KEY* */ #define BTRFS_UUID_TREE_OBJECTID 9ULL /* for storing balance parameters in the root tree */ #define BTRFS_BALANCE_OBJECTID -4ULL /* oprhan objectid for tracking unlinked/truncated files */ #define BTRFS_ORPHAN_OBJECTID -5ULL /* does write ahead logging to speed up fsyncs */ #define BTRFS_TREE_LOG_OBJECTID -6ULL #define BTRFS_TREE_LOG_FIXUP_OBJECTID -7ULL /* space balancing */ #define BTRFS_TREE_RELOC_OBJECTID -8ULL #define BTRFS_DATA_RELOC_TREE_OBJECTID -9ULL /* * extent checksums all have this objectid * this allows them to share the logging tree * for fsyncs */ #define BTRFS_EXTENT_CSUM_OBJECTID -10ULL /* For storing free space cache */ #define BTRFS_FREE_SPACE_OBJECTID -11ULL /* * The inode number assigned to the special inode for sotring * free ino cache */ #define BTRFS_FREE_INO_OBJECTID -12ULL /* dummy objectid represents multiple objectids */ #define BTRFS_MULTIPLE_OBJECTIDS -255ULL /* * All files have objectids in this range. */ #define BTRFS_FIRST_FREE_OBJECTID 256ULL #define BTRFS_LAST_FREE_OBJECTID -256ULL #define BTRFS_FIRST_CHUNK_TREE_OBJECTID 256ULL /* * the device items go into the chunk tree. The key is in the form * [ 1 BTRFS_DEV_ITEM_KEY device_id ] */ #define BTRFS_DEV_ITEMS_OBJECTID 1ULL /* * the max metadata block size. This limit is somewhat artificial, * but the memmove costs go through the roof for larger blocks. */ #define BTRFS_MAX_METADATA_BLOCKSIZE 65536 /* * we can actually store much bigger names, but lets not confuse the rest * of linux */ #define BTRFS_NAME_LEN 255 /* * Theoretical limit is larger, but we keep this down to a sane * value. That should limit greatly the possibility of collisions on * inode ref items. */ #define BTRFS_LINK_MAX 65535U /* 32 bytes in various csum fields */ #define BTRFS_CSUM_SIZE 32 /* csum types */ #define BTRFS_CSUM_TYPE_CRC32 0 static int btrfs_csum_sizes[] = { 4, 0 }; /* four bytes for CRC32 */ #define BTRFS_CRC32_SIZE 4 #define BTRFS_EMPTY_DIR_SIZE 0 #define BTRFS_FT_UNKNOWN 0 #define BTRFS_FT_REG_FILE 1 #define BTRFS_FT_DIR 2 #define BTRFS_FT_CHRDEV 3 #define BTRFS_FT_BLKDEV 4 #define BTRFS_FT_FIFO 5 #define BTRFS_FT_SOCK 6 #define BTRFS_FT_SYMLINK 7 #define BTRFS_FT_XATTR 8 #define BTRFS_FT_MAX 9 #define BTRFS_ROOT_SUBVOL_RDONLY (1ULL << 0) /* * the key defines the order in the tree, and so it also defines (optimal) * block layout. objectid corresonds to the inode number. The flags * tells us things about the object, and is a kind of stream selector. * so for a given inode, keys with flags of 1 might refer to the inode * data, flags of 2 may point to file data in the btree and flags == 3 * may point to extents. * * offset is the starting byte offset for this key in the stream. * * btrfs_disk_key is in disk byte order. struct btrfs_key is always * in cpu native order. Otherwise they are identical and their sizes * should be the same (ie both packed) */ struct btrfs_disk_key { __le64 objectid; u8 type; __le64 offset; } __attribute__ ((__packed__)); struct btrfs_key { u64 objectid; u8 type; u64 offset; } __attribute__ ((__packed__)); struct btrfs_mapping_tree { struct cache_tree cache_tree; }; #define BTRFS_UUID_SIZE 16 struct btrfs_dev_item { /* the internal btrfs device id */ __le64 devid; /* size of the device */ __le64 total_bytes; /* bytes used */ __le64 bytes_used; /* optimal io alignment for this device */ __le32 io_align; /* optimal io width for this device */ __le32 io_width; /* minimal io size for this device */ __le32 sector_size; /* type and info about this device */ __le64 type; /* expected generation for this device */ __le64 generation; /* * starting byte of this partition on the device, * to allowr for stripe alignment in the future */ __le64 start_offset; /* grouping information for allocation decisions */ __le32 dev_group; /* seek speed 0-100 where 100 is fastest */ u8 seek_speed; /* bandwidth 0-100 where 100 is fastest */ u8 bandwidth; /* btrfs generated uuid for this device */ u8 uuid[BTRFS_UUID_SIZE]; /* uuid of FS who owns this device */ u8 fsid[BTRFS_UUID_SIZE]; } __attribute__ ((__packed__)); struct btrfs_stripe { __le64 devid; __le64 offset; u8 dev_uuid[BTRFS_UUID_SIZE]; } __attribute__ ((__packed__)); struct btrfs_chunk { /* size of this chunk in bytes */ __le64 length; /* objectid of the root referencing this chunk */ __le64 owner; __le64 stripe_len; __le64 type; /* optimal io alignment for this chunk */ __le32 io_align; /* optimal io width for this chunk */ __le32 io_width; /* minimal io size for this chunk */ __le32 sector_size; /* 2^16 stripes is quite a lot, a second limit is the size of a single * item in the btree */ __le16 num_stripes; /* sub stripes only matter for raid10 */ __le16 sub_stripes; struct btrfs_stripe stripe; /* additional stripes go here */ } __attribute__ ((__packed__)); #define BTRFS_FREE_SPACE_EXTENT 1 #define BTRFS_FREE_SPACE_BITMAP 2 struct btrfs_free_space_entry { __le64 offset; __le64 bytes; u8 type; } __attribute__ ((__packed__)); struct btrfs_free_space_header { struct btrfs_disk_key location; __le64 generation; __le64 num_entries; __le64 num_bitmaps; } __attribute__ ((__packed__)); static inline unsigned long btrfs_chunk_item_size(int num_stripes) { BUG_ON(num_stripes == 0); return sizeof(struct btrfs_chunk) + sizeof(struct btrfs_stripe) * (num_stripes - 1); } #define BTRFS_HEADER_FLAG_WRITTEN (1ULL << 0) #define BTRFS_HEADER_FLAG_RELOC (1ULL << 1) #define BTRFS_SUPER_FLAG_SEEDING (1ULL << 32) #define BTRFS_SUPER_FLAG_METADUMP (1ULL << 33) #define BTRFS_BACKREF_REV_MAX 256 #define BTRFS_BACKREF_REV_SHIFT 56 #define BTRFS_BACKREF_REV_MASK (((u64)BTRFS_BACKREF_REV_MAX - 1) << \ BTRFS_BACKREF_REV_SHIFT) #define BTRFS_OLD_BACKREF_REV 0 #define BTRFS_MIXED_BACKREF_REV 1 /* * every tree block (leaf or node) starts with this header. */ struct btrfs_header { /* these first four must match the super block */ u8 csum[BTRFS_CSUM_SIZE]; u8 fsid[BTRFS_FSID_SIZE]; /* FS specific uuid */ __le64 bytenr; /* which block this node is supposed to live in */ __le64 flags; /* allowed to be different from the super from here on down */ u8 chunk_tree_uuid[BTRFS_UUID_SIZE]; __le64 generation; __le64 owner; __le32 nritems; u8 level; } __attribute__ ((__packed__)); #define BTRFS_NODEPTRS_PER_BLOCK(r) (((r)->nodesize - \ sizeof(struct btrfs_header)) / \ sizeof(struct btrfs_key_ptr)) #define __BTRFS_LEAF_DATA_SIZE(bs) ((bs) - sizeof(struct btrfs_header)) #define BTRFS_LEAF_DATA_SIZE(r) (__BTRFS_LEAF_DATA_SIZE(r->leafsize)) #define BTRFS_MAX_INLINE_DATA_SIZE(r) (BTRFS_LEAF_DATA_SIZE(r) - \ sizeof(struct btrfs_item) - \ sizeof(struct btrfs_file_extent_item)) #define BTRFS_MAX_XATTR_SIZE(r) (BTRFS_LEAF_DATA_SIZE(r) - \ sizeof(struct btrfs_item) -\ sizeof(struct btrfs_dir_item)) /* * this is a very generous portion of the super block, giving us * room to translate 14 chunks with 3 stripes each. */ #define BTRFS_SYSTEM_CHUNK_ARRAY_SIZE 2048 #define BTRFS_LABEL_SIZE 256 /* * just in case we somehow lose the roots and are not able to mount, * we store an array of the roots from previous transactions * in the super. */ #define BTRFS_NUM_BACKUP_ROOTS 4 struct btrfs_root_backup { __le64 tree_root; __le64 tree_root_gen; __le64 chunk_root; __le64 chunk_root_gen; __le64 extent_root; __le64 extent_root_gen; __le64 fs_root; __le64 fs_root_gen; __le64 dev_root; __le64 dev_root_gen; __le64 csum_root; __le64 csum_root_gen; __le64 total_bytes; __le64 bytes_used; __le64 num_devices; /* future */ __le64 unsed_64[4]; u8 tree_root_level; u8 chunk_root_level; u8 extent_root_level; u8 fs_root_level; u8 dev_root_level; u8 csum_root_level; /* future and to align */ u8 unused_8[10]; } __attribute__ ((__packed__)); /* * the super block basically lists the main trees of the FS * it currently lacks any block count etc etc */ struct btrfs_super_block { u8 csum[BTRFS_CSUM_SIZE]; /* the first 3 fields must match struct btrfs_header */ u8 fsid[BTRFS_FSID_SIZE]; /* FS specific uuid */ __le64 bytenr; /* this block number */ __le64 flags; /* allowed to be different from the btrfs_header from here own down */ __le64 magic; __le64 generation; __le64 root; __le64 chunk_root; __le64 log_root; /* this will help find the new super based on the log root */ __le64 log_root_transid; __le64 total_bytes; __le64 bytes_used; __le64 root_dir_objectid; __le64 num_devices; __le32 sectorsize; __le32 nodesize; __le32 leafsize; __le32 stripesize; __le32 sys_chunk_array_size; __le64 chunk_root_generation; __le64 compat_flags; __le64 compat_ro_flags; __le64 incompat_flags; __le16 csum_type; u8 root_level; u8 chunk_root_level; u8 log_root_level; struct btrfs_dev_item dev_item; char label[BTRFS_LABEL_SIZE]; __le64 cache_generation; __le64 uuid_tree_generation; /* future expansion */ __le64 reserved[30]; u8 sys_chunk_array[BTRFS_SYSTEM_CHUNK_ARRAY_SIZE]; struct btrfs_root_backup super_roots[BTRFS_NUM_BACKUP_ROOTS]; } __attribute__ ((__packed__)); /* * Compat flags that we support. If any incompat flags are set other than the * ones specified below then we will fail to mount */ #define BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF (1ULL << 0) #define BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL (1ULL << 1) #define BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS (1ULL << 2) #define BTRFS_FEATURE_INCOMPAT_COMPRESS_LZO (1ULL << 3) /* * some patches floated around with a second compression method * lets save that incompat here for when they do get in * Note we don't actually support it, we're just reserving the * number */ #define BTRFS_FEATURE_INCOMPAT_COMPRESS_LZOv2 (1ULL << 4) /* * older kernels tried to do bigger metadata blocks, but the * code was pretty buggy. Lets not let them try anymore. */ #define BTRFS_FEATURE_INCOMPAT_BIG_METADATA (1ULL << 5) #define BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF (1ULL << 6) #define BTRFS_FEATURE_INCOMPAT_RAID56 (1ULL << 7) #define BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA (1ULL << 8) #define BTRFS_FEATURE_INCOMPAT_NO_HOLES (1ULL << 9) #define BTRFS_FEATURE_COMPAT_SUPP 0ULL #define BTRFS_FEATURE_COMPAT_RO_SUPP 0ULL #define BTRFS_FEATURE_INCOMPAT_SUPP \ (BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF | \ BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL | \ BTRFS_FEATURE_INCOMPAT_COMPRESS_LZO | \ BTRFS_FEATURE_INCOMPAT_BIG_METADATA | \ BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF | \ BTRFS_FEATURE_INCOMPAT_RAID56 | \ BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS | \ BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA | \ BTRFS_FEATURE_INCOMPAT_NO_HOLES) /* * A leaf is full of items. offset and size tell us where to find * the item in the leaf (relative to the start of the data area) */ struct btrfs_item { struct btrfs_disk_key key; __le32 offset; __le32 size; } __attribute__ ((__packed__)); /* * leaves have an item area and a data area: * [item0, item1....itemN] [free space] [dataN...data1, data0] * * The data is separate from the items to get the keys closer together * during searches. */ struct btrfs_leaf { struct btrfs_header header; struct btrfs_item items[]; } __attribute__ ((__packed__)); /* * all non-leaf blocks are nodes, they hold only keys and pointers to * other blocks */ struct btrfs_key_ptr { struct btrfs_disk_key key; __le64 blockptr; __le64 generation; } __attribute__ ((__packed__)); struct btrfs_node { struct btrfs_header header; struct btrfs_key_ptr ptrs[]; } __attribute__ ((__packed__)); /* * btrfs_paths remember the path taken from the root down to the leaf. * level 0 is always the leaf, and nodes[1...BTRFS_MAX_LEVEL] will point * to any other levels that are present. * * The slots array records the index of the item or block pointer * used while walking the tree. */ struct btrfs_path { struct extent_buffer *nodes[BTRFS_MAX_LEVEL]; int slots[BTRFS_MAX_LEVEL]; /* if there is real range locking, this locks field will change */ int locks[BTRFS_MAX_LEVEL]; int reada; /* keep some upper locks as we walk down */ int lowest_level; /* * set by btrfs_split_item, tells search_slot to keep all locks * and to force calls to keep space in the nodes */ unsigned int search_for_split:1; unsigned int skip_check_block:1; }; /* * items in the extent btree are used to record the objectid of the * owner of the block and the number of references */ struct btrfs_extent_item { __le64 refs; __le64 generation; __le64 flags; } __attribute__ ((__packed__)); struct btrfs_extent_item_v0 { __le32 refs; } __attribute__ ((__packed__)); #define BTRFS_MAX_EXTENT_ITEM_SIZE(r) ((BTRFS_LEAF_DATA_SIZE(r) >> 4) - \ sizeof(struct btrfs_item)) #define BTRFS_EXTENT_FLAG_DATA (1ULL << 0) #define BTRFS_EXTENT_FLAG_TREE_BLOCK (1ULL << 1) /* following flags only apply to tree blocks */ /* use full backrefs for extent pointers in the block*/ #define BTRFS_BLOCK_FLAG_FULL_BACKREF (1ULL << 8) struct btrfs_tree_block_info { struct btrfs_disk_key key; u8 level; } __attribute__ ((__packed__)); struct btrfs_extent_data_ref { __le64 root; __le64 objectid; __le64 offset; __le32 count; } __attribute__ ((__packed__)); struct btrfs_shared_data_ref { __le32 count; } __attribute__ ((__packed__)); struct btrfs_extent_inline_ref { u8 type; __le64 offset; } __attribute__ ((__packed__)); struct btrfs_extent_ref_v0 { __le64 root; __le64 generation; __le64 objectid; __le32 count; } __attribute__ ((__packed__)); /* dev extents record free space on individual devices. The owner * field points back to the chunk allocation mapping tree that allocated * the extent. The chunk tree uuid field is a way to double check the owner */ struct btrfs_dev_extent { __le64 chunk_tree; __le64 chunk_objectid; __le64 chunk_offset; __le64 length; u8 chunk_tree_uuid[BTRFS_UUID_SIZE]; } __attribute__ ((__packed__)); struct btrfs_inode_ref { __le64 index; __le16 name_len; /* name goes here */ } __attribute__ ((__packed__)); struct btrfs_inode_extref { __le64 parent_objectid; __le64 index; __le16 name_len; __u8 name[0]; /* name goes here */ } __attribute__ ((__packed__)); struct btrfs_timespec { __le64 sec; __le32 nsec; } __attribute__ ((__packed__)); typedef enum { BTRFS_COMPRESS_NONE = 0, BTRFS_COMPRESS_ZLIB = 1, BTRFS_COMPRESS_LZO = 2, BTRFS_COMPRESS_TYPES = 2, BTRFS_COMPRESS_LAST = 3, } btrfs_compression_type; /* we don't understand any encryption methods right now */ typedef enum { BTRFS_ENCRYPTION_NONE = 0, BTRFS_ENCRYPTION_LAST = 1, } btrfs_encryption_type; enum btrfs_tree_block_status { BTRFS_TREE_BLOCK_CLEAN, BTRFS_TREE_BLOCK_INVALID_NRITEMS, BTRFS_TREE_BLOCK_INVALID_PARENT_KEY, BTRFS_TREE_BLOCK_BAD_KEY_ORDER, BTRFS_TREE_BLOCK_INVALID_LEVEL, BTRFS_TREE_BLOCK_INVALID_FREE_SPACE, BTRFS_TREE_BLOCK_INVALID_OFFSETS, }; struct btrfs_inode_item { /* nfs style generation number */ __le64 generation; /* transid that last touched this inode */ __le64 transid; __le64 size; __le64 nbytes; __le64 block_group; __le32 nlink; __le32 uid; __le32 gid; __le32 mode; __le64 rdev; __le64 flags; /* modification sequence number for NFS */ __le64 sequence; /* * a little future expansion, for more than this we can * just grow the inode item and version it */ __le64 reserved[4]; struct btrfs_timespec atime; struct btrfs_timespec ctime; struct btrfs_timespec mtime; struct btrfs_timespec otime; } __attribute__ ((__packed__)); struct btrfs_dir_log_item { __le64 end; } __attribute__ ((__packed__)); struct btrfs_dir_item { struct btrfs_disk_key location; __le64 transid; __le16 data_len; __le16 name_len; u8 type; } __attribute__ ((__packed__)); struct btrfs_root_item_v0 { struct btrfs_inode_item inode; __le64 generation; __le64 root_dirid; __le64 bytenr; __le64 byte_limit; __le64 bytes_used; __le64 last_snapshot; __le64 flags; __le32 refs; struct btrfs_disk_key drop_progress; u8 drop_level; u8 level; } __attribute__ ((__packed__)); struct btrfs_root_item { struct btrfs_inode_item inode; __le64 generation; __le64 root_dirid; __le64 bytenr; __le64 byte_limit; __le64 bytes_used; __le64 last_snapshot; __le64 flags; __le32 refs; struct btrfs_disk_key drop_progress; u8 drop_level; u8 level; /* * The following fields appear after subvol_uuids+subvol_times * were introduced. */ /* * This generation number is used to test if the new fields are valid * and up to date while reading the root item. Everytime the root item * is written out, the "generation" field is copied into this field. If * anyone ever mounted the fs with an older kernel, we will have * mismatching generation values here and thus must invalidate the * new fields. See btrfs_update_root and btrfs_find_last_root for * details. * the offset of generation_v2 is also used as the start for the memset * when invalidating the fields. */ __le64 generation_v2; u8 uuid[BTRFS_UUID_SIZE]; u8 parent_uuid[BTRFS_UUID_SIZE]; u8 received_uuid[BTRFS_UUID_SIZE]; __le64 ctransid; /* updated when an inode changes */ __le64 otransid; /* trans when created */ __le64 stransid; /* trans when sent. non-zero for received subvol */ __le64 rtransid; /* trans when received. non-zero for received subvol */ struct btrfs_timespec ctime; struct btrfs_timespec otime; struct btrfs_timespec stime; struct btrfs_timespec rtime; __le64 reserved[8]; /* for future */ } __attribute__ ((__packed__)); /* * this is used for both forward and backward root refs */ struct btrfs_root_ref { __le64 dirid; __le64 sequence; __le16 name_len; } __attribute__ ((__packed__)); #define BTRFS_FILE_EXTENT_INLINE 0 #define BTRFS_FILE_EXTENT_REG 1 #define BTRFS_FILE_EXTENT_PREALLOC 2 struct btrfs_file_extent_item { /* * transaction id that created this extent */ __le64 generation; /* * max number of bytes to hold this extent in ram * when we split a compressed extent we can't know how big * each of the resulting pieces will be. So, this is * an upper limit on the size of the extent in ram instead of * an exact limit. */ __le64 ram_bytes; /* * 32 bits for the various ways we might encode the data, * including compression and encryption. If any of these * are set to something a given disk format doesn't understand * it is treated like an incompat flag for reading and writing, * but not for stat. */ u8 compression; u8 encryption; __le16 other_encoding; /* spare for later use */ /* are we inline data or a real extent? */ u8 type; /* * disk space consumed by the extent, checksum blocks are included * in these numbers */ __le64 disk_bytenr; __le64 disk_num_bytes; /* * the logical offset in file blocks (no csums) * this extent record is for. This allows a file extent to point * into the middle of an existing extent on disk, sharing it * between two snapshots (useful if some bytes in the middle of the * extent have changed */ __le64 offset; /* * the logical number of file blocks (no csums included) */ __le64 num_bytes; } __attribute__ ((__packed__)); struct btrfs_csum_item { u8 csum; } __attribute__ ((__packed__)); /* * We don't want to overwrite 1M at the beginning of device, even though * there is our 1st superblock at 64k. Some possible reasons: * - the first 64k blank is useful for some boot loader/manager * - the first 1M could be scratched by buggy partitioner or somesuch */ #define BTRFS_BLOCK_RESERVED_1M_FOR_SUPER ((u64)1024 * 1024) /* tag for the radix tree of block groups in ram */ #define BTRFS_BLOCK_GROUP_DATA (1ULL << 0) #define BTRFS_BLOCK_GROUP_SYSTEM (1ULL << 1) #define BTRFS_BLOCK_GROUP_METADATA (1ULL << 2) #define BTRFS_BLOCK_GROUP_RAID0 (1ULL << 3) #define BTRFS_BLOCK_GROUP_RAID1 (1ULL << 4) #define BTRFS_BLOCK_GROUP_DUP (1ULL << 5) #define BTRFS_BLOCK_GROUP_RAID10 (1ULL << 6) #define BTRFS_BLOCK_GROUP_RAID5 (1ULL << 7) #define BTRFS_BLOCK_GROUP_RAID6 (1ULL << 8) #define BTRFS_BLOCK_GROUP_RESERVED BTRFS_AVAIL_ALLOC_BIT_SINGLE #define BTRFS_BLOCK_GROUP_TYPE_MASK (BTRFS_BLOCK_GROUP_DATA | \ BTRFS_BLOCK_GROUP_SYSTEM | \ BTRFS_BLOCK_GROUP_METADATA) #define BTRFS_BLOCK_GROUP_PROFILE_MASK (BTRFS_BLOCK_GROUP_RAID0 | \ BTRFS_BLOCK_GROUP_RAID1 | \ BTRFS_BLOCK_GROUP_RAID5 | \ BTRFS_BLOCK_GROUP_RAID6 | \ BTRFS_BLOCK_GROUP_DUP | \ BTRFS_BLOCK_GROUP_RAID10) /* used in struct btrfs_balance_args fields */ #define BTRFS_AVAIL_ALLOC_BIT_SINGLE (1ULL << 48) /* * GLOBAL_RSV does not exist as a on-disk block group type and is used * internally for exporting info about global block reserve from space infos */ #define BTRFS_SPACE_INFO_GLOBAL_RSV (1ULL << 49) #define BTRFS_QGROUP_STATUS_OFF 0 #define BTRFS_QGROUP_STATUS_ON 1 #define BTRFS_QGROUP_STATUS_SCANNING 2 #define BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT (1 << 0) struct btrfs_qgroup_status_item { __le64 version; __le64 generation; __le64 flags; __le64 scan; /* progress during scanning */ } __attribute__ ((__packed__)); struct btrfs_block_group_item { __le64 used; __le64 chunk_objectid; __le64 flags; } __attribute__ ((__packed__)); struct btrfs_qgroup_info_item { __le64 generation; __le64 referenced; __le64 referenced_compressed; __le64 exclusive; __le64 exclusive_compressed; } __attribute__ ((__packed__)); /* flags definition for qgroup limits */ #define BTRFS_QGROUP_LIMIT_MAX_RFER (1ULL << 0) #define BTRFS_QGROUP_LIMIT_MAX_EXCL (1ULL << 1) #define BTRFS_QGROUP_LIMIT_RSV_RFER (1ULL << 2) #define BTRFS_QGROUP_LIMIT_RSV_EXCL (1ULL << 3) #define BTRFS_QGROUP_LIMIT_RFER_CMPR (1ULL << 4) #define BTRFS_QGROUP_LIMIT_EXCL_CMPR (1ULL << 5) struct btrfs_qgroup_limit_item { __le64 flags; __le64 max_referenced; __le64 max_exclusive; __le64 rsv_referenced; __le64 rsv_exclusive; } __attribute__ ((__packed__)); struct btrfs_space_info { u64 flags; u64 total_bytes; u64 bytes_used; u64 bytes_pinned; int full; struct list_head list; }; struct btrfs_block_group_cache { struct cache_extent cache; struct btrfs_key key; struct btrfs_block_group_item item; struct btrfs_space_info *space_info; struct btrfs_free_space_ctl *free_space_ctl; u64 pinned; u64 flags; int cached; int ro; }; struct btrfs_extent_ops { int (*alloc_extent)(struct btrfs_root *root, u64 num_bytes, u64 hint_byte, struct btrfs_key *ins); int (*free_extent)(struct btrfs_root *root, u64 bytenr, u64 num_bytes); }; struct btrfs_device; struct btrfs_fs_devices; struct btrfs_fs_info { u8 fsid[BTRFS_FSID_SIZE]; u8 chunk_tree_uuid[BTRFS_UUID_SIZE]; struct btrfs_root *fs_root; struct btrfs_root *extent_root; struct btrfs_root *tree_root; struct btrfs_root *chunk_root; struct btrfs_root *dev_root; struct btrfs_root *csum_root; struct btrfs_root *quota_root; struct rb_root fs_root_tree; /* the log root tree is a directory of all the other log roots */ struct btrfs_root *log_root_tree; struct extent_io_tree extent_cache; struct extent_io_tree free_space_cache; struct extent_io_tree block_group_cache; struct extent_io_tree pinned_extents; struct extent_io_tree pending_del; struct extent_io_tree extent_ins; /* logical->physical extent mapping */ struct btrfs_mapping_tree mapping_tree; u64 generation; u64 last_trans_committed; u64 avail_data_alloc_bits; u64 avail_metadata_alloc_bits; u64 avail_system_alloc_bits; u64 data_alloc_profile; u64 metadata_alloc_profile; u64 system_alloc_profile; u64 alloc_start; struct btrfs_trans_handle *running_transaction; struct btrfs_super_block *super_copy; struct mutex fs_mutex; u64 super_bytenr; u64 total_pinned; struct btrfs_extent_ops *extent_ops; struct list_head dirty_cowonly_roots; struct list_head recow_ebs; struct btrfs_fs_devices *fs_devices; struct list_head space_info; int system_allocs; unsigned int readonly:1; unsigned int on_restoring:1; unsigned int is_chunk_recover:1; unsigned int quota_enabled:1; int (*free_extent_hook)(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 bytenr, u64 num_bytes, u64 parent, u64 root_objectid, u64 owner, u64 offset, int refs_to_drop); struct cache_tree *fsck_extent_cache; struct cache_tree *corrupt_blocks; }; /* * in ram representation of the tree. extent_root is used for all allocations * and for the extent tree extent_root root. */ struct btrfs_root { struct extent_buffer *node; struct extent_buffer *commit_root; struct btrfs_root_item root_item; struct btrfs_key root_key; struct btrfs_fs_info *fs_info; u64 objectid; u64 last_trans; /* data allocations are done in sectorsize units */ u32 sectorsize; /* node allocations are done in nodesize units */ u32 nodesize; /* leaf allocations are done in leafsize units */ u32 leafsize; /* leaf allocations are done in leafsize units */ u32 stripesize; int ref_cows; int track_dirty; u32 type; u64 highest_inode; u64 last_inode_alloc; /* the dirty list is only used by non-reference counted roots */ struct list_head dirty_list; struct rb_node rb_node; }; /* * inode items have the data typically returned from stat and store other * info about object characteristics. There is one for every file and dir in * the FS */ #define BTRFS_INODE_ITEM_KEY 1 #define BTRFS_INODE_REF_KEY 12 #define BTRFS_INODE_EXTREF_KEY 13 #define BTRFS_XATTR_ITEM_KEY 24 #define BTRFS_ORPHAN_ITEM_KEY 48 #define BTRFS_DIR_LOG_ITEM_KEY 60 #define BTRFS_DIR_LOG_INDEX_KEY 72 /* * dir items are the name -> inode pointers in a directory. There is one * for every name in a directory. */ #define BTRFS_DIR_ITEM_KEY 84 #define BTRFS_DIR_INDEX_KEY 96 /* * extent data is for file data */ #define BTRFS_EXTENT_DATA_KEY 108 /* * csum items have the checksums for data in the extents */ #define BTRFS_CSUM_ITEM_KEY 120 /* * extent csums are stored in a separate tree and hold csums for * an entire extent on disk. */ #define BTRFS_EXTENT_CSUM_KEY 128 /* * root items point to tree roots. There are typically in the root * tree used by the super block to find all the other trees */ #define BTRFS_ROOT_ITEM_KEY 132 /* * root backrefs tie subvols and snapshots to the directory entries that * reference them */ #define BTRFS_ROOT_BACKREF_KEY 144 /* * root refs make a fast index for listing all of the snapshots and * subvolumes referenced by a given root. They point directly to the * directory item in the root that references the subvol */ #define BTRFS_ROOT_REF_KEY 156 /* * extent items are in the extent map tree. These record which blocks * are used, and how many references there are to each block */ #define BTRFS_EXTENT_ITEM_KEY 168 /* * The same as the BTRFS_EXTENT_ITEM_KEY, except it's metadata we already know * the length, so we save the level in key->offset instead of the length. */ #define BTRFS_METADATA_ITEM_KEY 169 #define BTRFS_TREE_BLOCK_REF_KEY 176 #define BTRFS_EXTENT_DATA_REF_KEY 178 /* old style extent backrefs */ #define BTRFS_EXTENT_REF_V0_KEY 180 #define BTRFS_SHARED_BLOCK_REF_KEY 182 #define BTRFS_SHARED_DATA_REF_KEY 184 /* * block groups give us hints into the extent allocation trees. Which * blocks are free etc etc */ #define BTRFS_BLOCK_GROUP_ITEM_KEY 192 #define BTRFS_DEV_EXTENT_KEY 204 #define BTRFS_DEV_ITEM_KEY 216 #define BTRFS_CHUNK_ITEM_KEY 228 #define BTRFS_BALANCE_ITEM_KEY 248 /* * quota groups */ #define BTRFS_QGROUP_STATUS_KEY 240 #define BTRFS_QGROUP_INFO_KEY 242 #define BTRFS_QGROUP_LIMIT_KEY 244 #define BTRFS_QGROUP_RELATION_KEY 246 /* * Persistently stores the io stats in the device tree. * One key for all stats, (0, BTRFS_DEV_STATS_KEY, devid). */ #define BTRFS_DEV_STATS_KEY 249 /* * Persistently stores the device replace state in the device tree. * The key is built like this: (0, BTRFS_DEV_REPLACE_KEY, 0). */ #define BTRFS_DEV_REPLACE_KEY 250 /* * Stores items that allow to quickly map UUIDs to something else. * These items are part of the filesystem UUID tree. * The key is built like this: * (UUID_upper_64_bits, BTRFS_UUID_KEY*, UUID_lower_64_bits). */ #if BTRFS_UUID_SIZE != 16 #error "UUID items require BTRFS_UUID_SIZE == 16!" #endif #define BTRFS_UUID_KEY_SUBVOL 251 /* for UUIDs assigned to subvols */ #define BTRFS_UUID_KEY_RECEIVED_SUBVOL 252 /* for UUIDs assigned to * received subvols */ /* * string items are for debugging. They just store a short string of * data in the FS */ #define BTRFS_STRING_ITEM_KEY 253 /* * Inode flags */ #define BTRFS_INODE_NODATASUM (1 << 0) #define BTRFS_INODE_NODATACOW (1 << 1) #define BTRFS_INODE_READONLY (1 << 2) #define read_eb_member(eb, ptr, type, member, result) ( \ read_extent_buffer(eb, (char *)(result), \ ((unsigned long)(ptr)) + \ offsetof(type, member), \ sizeof(((type *)0)->member))) #define write_eb_member(eb, ptr, type, member, result) ( \ write_extent_buffer(eb, (char *)(result), \ ((unsigned long)(ptr)) + \ offsetof(type, member), \ sizeof(((type *)0)->member))) #define BTRFS_SETGET_HEADER_FUNCS(name, type, member, bits) \ static inline u##bits btrfs_##name(const struct extent_buffer *eb) \ { \ const struct btrfs_header *h = (struct btrfs_header *)eb->data; \ return le##bits##_to_cpu(h->member); \ } \ static inline void btrfs_set_##name(struct extent_buffer *eb, \ u##bits val) \ { \ struct btrfs_header *h = (struct btrfs_header *)eb->data; \ h->member = cpu_to_le##bits(val); \ } #define BTRFS_SETGET_FUNCS(name, type, member, bits) \ static inline u##bits btrfs_##name(const struct extent_buffer *eb, \ const type *s) \ { \ unsigned long offset = (unsigned long)s; \ const type *p = (type *) (eb->data + offset); \ return get_unaligned_le##bits(&p->member); \ } \ static inline void btrfs_set_##name(struct extent_buffer *eb, \ type *s, u##bits val) \ { \ unsigned long offset = (unsigned long)s; \ type *p = (type *) (eb->data + offset); \ put_unaligned_le##bits(val, &p->member); \ } #define BTRFS_SETGET_STACK_FUNCS(name, type, member, bits) \ static inline u##bits btrfs_##name(const type *s) \ { \ return le##bits##_to_cpu(s->member); \ } \ static inline void btrfs_set_##name(type *s, u##bits val) \ { \ s->member = cpu_to_le##bits(val); \ } BTRFS_SETGET_FUNCS(device_type, struct btrfs_dev_item, type, 64); BTRFS_SETGET_FUNCS(device_total_bytes, struct btrfs_dev_item, total_bytes, 64); BTRFS_SETGET_FUNCS(device_bytes_used, struct btrfs_dev_item, bytes_used, 64); BTRFS_SETGET_FUNCS(device_io_align, struct btrfs_dev_item, io_align, 32); BTRFS_SETGET_FUNCS(device_io_width, struct btrfs_dev_item, io_width, 32); BTRFS_SETGET_FUNCS(device_start_offset, struct btrfs_dev_item, start_offset, 64); BTRFS_SETGET_FUNCS(device_sector_size, struct btrfs_dev_item, sector_size, 32); BTRFS_SETGET_FUNCS(device_id, struct btrfs_dev_item, devid, 64); BTRFS_SETGET_FUNCS(device_group, struct btrfs_dev_item, dev_group, 32); BTRFS_SETGET_FUNCS(device_seek_speed, struct btrfs_dev_item, seek_speed, 8); BTRFS_SETGET_FUNCS(device_bandwidth, struct btrfs_dev_item, bandwidth, 8); BTRFS_SETGET_FUNCS(device_generation, struct btrfs_dev_item, generation, 64); BTRFS_SETGET_STACK_FUNCS(stack_device_type, struct btrfs_dev_item, type, 64); BTRFS_SETGET_STACK_FUNCS(stack_device_total_bytes, struct btrfs_dev_item, total_bytes, 64); BTRFS_SETGET_STACK_FUNCS(stack_device_bytes_used, struct btrfs_dev_item, bytes_used, 64); BTRFS_SETGET_STACK_FUNCS(stack_device_io_align, struct btrfs_dev_item, io_align, 32); BTRFS_SETGET_STACK_FUNCS(stack_device_io_width, struct btrfs_dev_item, io_width, 32); BTRFS_SETGET_STACK_FUNCS(stack_device_sector_size, struct btrfs_dev_item, sector_size, 32); BTRFS_SETGET_STACK_FUNCS(stack_device_id, struct btrfs_dev_item, devid, 64); BTRFS_SETGET_STACK_FUNCS(stack_device_group, struct btrfs_dev_item, dev_group, 32); BTRFS_SETGET_STACK_FUNCS(stack_device_seek_speed, struct btrfs_dev_item, seek_speed, 8); BTRFS_SETGET_STACK_FUNCS(stack_device_bandwidth, struct btrfs_dev_item, bandwidth, 8); BTRFS_SETGET_STACK_FUNCS(stack_device_generation, struct btrfs_dev_item, generation, 64); static inline char *btrfs_device_uuid(struct btrfs_dev_item *d) { return (char *)d + offsetof(struct btrfs_dev_item, uuid); } static inline char *btrfs_device_fsid(struct btrfs_dev_item *d) { return (char *)d + offsetof(struct btrfs_dev_item, fsid); } BTRFS_SETGET_FUNCS(chunk_length, struct btrfs_chunk, length, 64); BTRFS_SETGET_FUNCS(chunk_owner, struct btrfs_chunk, owner, 64); BTRFS_SETGET_FUNCS(chunk_stripe_len, struct btrfs_chunk, stripe_len, 64); BTRFS_SETGET_FUNCS(chunk_io_align, struct btrfs_chunk, io_align, 32); BTRFS_SETGET_FUNCS(chunk_io_width, struct btrfs_chunk, io_width, 32); BTRFS_SETGET_FUNCS(chunk_sector_size, struct btrfs_chunk, sector_size, 32); BTRFS_SETGET_FUNCS(chunk_type, struct btrfs_chunk, type, 64); BTRFS_SETGET_FUNCS(chunk_num_stripes, struct btrfs_chunk, num_stripes, 16); BTRFS_SETGET_FUNCS(chunk_sub_stripes, struct btrfs_chunk, sub_stripes, 16); BTRFS_SETGET_FUNCS(stripe_devid, struct btrfs_stripe, devid, 64); BTRFS_SETGET_FUNCS(stripe_offset, struct btrfs_stripe, offset, 64); static inline char *btrfs_stripe_dev_uuid(struct btrfs_stripe *s) { return (char *)s + offsetof(struct btrfs_stripe, dev_uuid); } BTRFS_SETGET_STACK_FUNCS(stack_chunk_length, struct btrfs_chunk, length, 64); BTRFS_SETGET_STACK_FUNCS(stack_chunk_owner, struct btrfs_chunk, owner, 64); BTRFS_SETGET_STACK_FUNCS(stack_chunk_stripe_len, struct btrfs_chunk, stripe_len, 64); BTRFS_SETGET_STACK_FUNCS(stack_chunk_io_align, struct btrfs_chunk, io_align, 32); BTRFS_SETGET_STACK_FUNCS(stack_chunk_io_width, struct btrfs_chunk, io_width, 32); BTRFS_SETGET_STACK_FUNCS(stack_chunk_sector_size, struct btrfs_chunk, sector_size, 32); BTRFS_SETGET_STACK_FUNCS(stack_chunk_type, struct btrfs_chunk, type, 64); BTRFS_SETGET_STACK_FUNCS(stack_chunk_num_stripes, struct btrfs_chunk, num_stripes, 16); BTRFS_SETGET_STACK_FUNCS(stack_chunk_sub_stripes, struct btrfs_chunk, sub_stripes, 16); BTRFS_SETGET_STACK_FUNCS(stack_stripe_devid, struct btrfs_stripe, devid, 64); BTRFS_SETGET_STACK_FUNCS(stack_stripe_offset, struct btrfs_stripe, offset, 64); static inline struct btrfs_stripe *btrfs_stripe_nr(struct btrfs_chunk *c, int nr) { unsigned long offset = (unsigned long)c; offset += offsetof(struct btrfs_chunk, stripe); offset += nr * sizeof(struct btrfs_stripe); return (struct btrfs_stripe *)offset; } static inline char *btrfs_stripe_dev_uuid_nr(struct btrfs_chunk *c, int nr) { return btrfs_stripe_dev_uuid(btrfs_stripe_nr(c, nr)); } static inline u64 btrfs_stripe_offset_nr(struct extent_buffer *eb, struct btrfs_chunk *c, int nr) { return btrfs_stripe_offset(eb, btrfs_stripe_nr(c, nr)); } static inline void btrfs_set_stripe_offset_nr(struct extent_buffer *eb, struct btrfs_chunk *c, int nr, u64 val) { btrfs_set_stripe_offset(eb, btrfs_stripe_nr(c, nr), val); } static inline u64 btrfs_stripe_devid_nr(struct extent_buffer *eb, struct btrfs_chunk *c, int nr) { return btrfs_stripe_devid(eb, btrfs_stripe_nr(c, nr)); } static inline void btrfs_set_stripe_devid_nr(struct extent_buffer *eb, struct btrfs_chunk *c, int nr, u64 val) { btrfs_set_stripe_devid(eb, btrfs_stripe_nr(c, nr), val); } /* struct btrfs_block_group_item */ BTRFS_SETGET_STACK_FUNCS(block_group_used, struct btrfs_block_group_item, used, 64); BTRFS_SETGET_FUNCS(disk_block_group_used, struct btrfs_block_group_item, used, 64); BTRFS_SETGET_STACK_FUNCS(block_group_chunk_objectid, struct btrfs_block_group_item, chunk_objectid, 64); BTRFS_SETGET_FUNCS(disk_block_group_chunk_objectid, struct btrfs_block_group_item, chunk_objectid, 64); BTRFS_SETGET_FUNCS(disk_block_group_flags, struct btrfs_block_group_item, flags, 64); BTRFS_SETGET_STACK_FUNCS(block_group_flags, struct btrfs_block_group_item, flags, 64); /* struct btrfs_inode_ref */ BTRFS_SETGET_FUNCS(inode_ref_name_len, struct btrfs_inode_ref, name_len, 16); BTRFS_SETGET_STACK_FUNCS(stack_inode_ref_name_len, struct btrfs_inode_ref, name_len, 16); BTRFS_SETGET_FUNCS(inode_ref_index, struct btrfs_inode_ref, index, 64); /* struct btrfs_inode_extref */ BTRFS_SETGET_FUNCS(inode_extref_parent, struct btrfs_inode_extref, parent_objectid, 64); BTRFS_SETGET_FUNCS(inode_extref_name_len, struct btrfs_inode_extref, name_len, 16); BTRFS_SETGET_FUNCS(inode_extref_index, struct btrfs_inode_extref, index, 64); /* struct btrfs_inode_item */ BTRFS_SETGET_FUNCS(inode_generation, struct btrfs_inode_item, generation, 64); BTRFS_SETGET_FUNCS(inode_sequence, struct btrfs_inode_item, sequence, 64); BTRFS_SETGET_FUNCS(inode_transid, struct btrfs_inode_item, transid, 64); BTRFS_SETGET_FUNCS(inode_size, struct btrfs_inode_item, size, 64); BTRFS_SETGET_FUNCS(inode_nbytes, struct btrfs_inode_item, nbytes, 64); BTRFS_SETGET_FUNCS(inode_block_group, struct btrfs_inode_item, block_group, 64); BTRFS_SETGET_FUNCS(inode_nlink, struct btrfs_inode_item, nlink, 32); BTRFS_SETGET_FUNCS(inode_uid, struct btrfs_inode_item, uid, 32); BTRFS_SETGET_FUNCS(inode_gid, struct btrfs_inode_item, gid, 32); BTRFS_SETGET_FUNCS(inode_mode, struct btrfs_inode_item, mode, 32); BTRFS_SETGET_FUNCS(inode_rdev, struct btrfs_inode_item, rdev, 64); BTRFS_SETGET_FUNCS(inode_flags, struct btrfs_inode_item, flags, 64); BTRFS_SETGET_STACK_FUNCS(stack_inode_generation, struct btrfs_inode_item, generation, 64); BTRFS_SETGET_STACK_FUNCS(stack_inode_sequence, struct btrfs_inode_item, generation, 64); BTRFS_SETGET_STACK_FUNCS(stack_inode_size, struct btrfs_inode_item, size, 64); BTRFS_SETGET_STACK_FUNCS(stack_inode_nbytes, struct btrfs_inode_item, nbytes, 64); BTRFS_SETGET_STACK_FUNCS(stack_inode_block_group, struct btrfs_inode_item, block_group, 64); BTRFS_SETGET_STACK_FUNCS(stack_inode_nlink, struct btrfs_inode_item, nlink, 32); BTRFS_SETGET_STACK_FUNCS(stack_inode_uid, struct btrfs_inode_item, uid, 32); BTRFS_SETGET_STACK_FUNCS(stack_inode_gid, struct btrfs_inode_item, gid, 32); BTRFS_SETGET_STACK_FUNCS(stack_inode_mode, struct btrfs_inode_item, mode, 32); BTRFS_SETGET_STACK_FUNCS(stack_inode_rdev, struct btrfs_inode_item, rdev, 64); BTRFS_SETGET_STACK_FUNCS(stack_inode_flags, struct btrfs_inode_item, flags, 64); static inline struct btrfs_timespec * btrfs_inode_atime(struct btrfs_inode_item *inode_item) { unsigned long ptr = (unsigned long)inode_item; ptr += offsetof(struct btrfs_inode_item, atime); return (struct btrfs_timespec *)ptr; } static inline struct btrfs_timespec * btrfs_inode_mtime(struct btrfs_inode_item *inode_item) { unsigned long ptr = (unsigned long)inode_item; ptr += offsetof(struct btrfs_inode_item, mtime); return (struct btrfs_timespec *)ptr; } static inline struct btrfs_timespec * btrfs_inode_ctime(struct btrfs_inode_item *inode_item) { unsigned long ptr = (unsigned long)inode_item; ptr += offsetof(struct btrfs_inode_item, ctime); return (struct btrfs_timespec *)ptr; } static inline struct btrfs_timespec * btrfs_inode_otime(struct btrfs_inode_item *inode_item) { unsigned long ptr = (unsigned long)inode_item; ptr += offsetof(struct btrfs_inode_item, otime); return (struct btrfs_timespec *)ptr; } BTRFS_SETGET_FUNCS(timespec_sec, struct btrfs_timespec, sec, 64); BTRFS_SETGET_FUNCS(timespec_nsec, struct btrfs_timespec, nsec, 32); BTRFS_SETGET_STACK_FUNCS(stack_timespec_sec, struct btrfs_timespec, sec, 64); BTRFS_SETGET_STACK_FUNCS(stack_timespec_nsec, struct btrfs_timespec, nsec, 32); /* struct btrfs_dev_extent */ BTRFS_SETGET_FUNCS(dev_extent_chunk_tree, struct btrfs_dev_extent, chunk_tree, 64); BTRFS_SETGET_FUNCS(dev_extent_chunk_objectid, struct btrfs_dev_extent, chunk_objectid, 64); BTRFS_SETGET_FUNCS(dev_extent_chunk_offset, struct btrfs_dev_extent, chunk_offset, 64); BTRFS_SETGET_FUNCS(dev_extent_length, struct btrfs_dev_extent, length, 64); static inline u8 *btrfs_dev_extent_chunk_tree_uuid(struct btrfs_dev_extent *dev) { unsigned long ptr = offsetof(struct btrfs_dev_extent, chunk_tree_uuid); return (u8 *)((unsigned long)dev + ptr); } /* struct btrfs_extent_item */ BTRFS_SETGET_FUNCS(extent_refs, struct btrfs_extent_item, refs, 64); BTRFS_SETGET_STACK_FUNCS(stack_extent_refs, struct btrfs_extent_item, refs, 64); BTRFS_SETGET_FUNCS(extent_generation, struct btrfs_extent_item, generation, 64); BTRFS_SETGET_FUNCS(extent_flags, struct btrfs_extent_item, flags, 64); BTRFS_SETGET_STACK_FUNCS(stack_extent_flags, struct btrfs_extent_item, flags, 64); BTRFS_SETGET_FUNCS(extent_refs_v0, struct btrfs_extent_item_v0, refs, 32); BTRFS_SETGET_FUNCS(tree_block_level, struct btrfs_tree_block_info, level, 8); static inline void btrfs_tree_block_key(struct extent_buffer *eb, struct btrfs_tree_block_info *item, struct btrfs_disk_key *key) { read_eb_member(eb, item, struct btrfs_tree_block_info, key, key); } static inline void btrfs_set_tree_block_key(struct extent_buffer *eb, struct btrfs_tree_block_info *item, struct btrfs_disk_key *key) { write_eb_member(eb, item, struct btrfs_tree_block_info, key, key); } BTRFS_SETGET_FUNCS(extent_data_ref_root, struct btrfs_extent_data_ref, root, 64); BTRFS_SETGET_FUNCS(extent_data_ref_objectid, struct btrfs_extent_data_ref, objectid, 64); BTRFS_SETGET_FUNCS(extent_data_ref_offset, struct btrfs_extent_data_ref, offset, 64); BTRFS_SETGET_FUNCS(extent_data_ref_count, struct btrfs_extent_data_ref, count, 32); BTRFS_SETGET_FUNCS(shared_data_ref_count, struct btrfs_shared_data_ref, count, 32); BTRFS_SETGET_FUNCS(extent_inline_ref_type, struct btrfs_extent_inline_ref, type, 8); BTRFS_SETGET_FUNCS(extent_inline_ref_offset, struct btrfs_extent_inline_ref, offset, 64); BTRFS_SETGET_STACK_FUNCS(stack_extent_inline_ref_type, struct btrfs_extent_inline_ref, type, 8); BTRFS_SETGET_STACK_FUNCS(stack_extent_inline_ref_offset, struct btrfs_extent_inline_ref, offset, 64); static inline u32 btrfs_extent_inline_ref_size(int type) { if (type == BTRFS_TREE_BLOCK_REF_KEY || type == BTRFS_SHARED_BLOCK_REF_KEY) return sizeof(struct btrfs_extent_inline_ref); if (type == BTRFS_SHARED_DATA_REF_KEY) return sizeof(struct btrfs_shared_data_ref) + sizeof(struct btrfs_extent_inline_ref); if (type == BTRFS_EXTENT_DATA_REF_KEY) return sizeof(struct btrfs_extent_data_ref) + offsetof(struct btrfs_extent_inline_ref, offset); BUG(); return 0; } BTRFS_SETGET_FUNCS(ref_root_v0, struct btrfs_extent_ref_v0, root, 64); BTRFS_SETGET_FUNCS(ref_generation_v0, struct btrfs_extent_ref_v0, generation, 64); BTRFS_SETGET_FUNCS(ref_objectid_v0, struct btrfs_extent_ref_v0, objectid, 64); BTRFS_SETGET_FUNCS(ref_count_v0, struct btrfs_extent_ref_v0, count, 32); /* struct btrfs_node */ BTRFS_SETGET_FUNCS(key_blockptr, struct btrfs_key_ptr, blockptr, 64); BTRFS_SETGET_FUNCS(key_generation, struct btrfs_key_ptr, generation, 64); static inline u64 btrfs_node_blockptr(struct extent_buffer *eb, int nr) { unsigned long ptr; ptr = offsetof(struct btrfs_node, ptrs) + sizeof(struct btrfs_key_ptr) * nr; return btrfs_key_blockptr(eb, (struct btrfs_key_ptr *)ptr); } static inline void btrfs_set_node_blockptr(struct extent_buffer *eb, int nr, u64 val) { unsigned long ptr; ptr = offsetof(struct btrfs_node, ptrs) + sizeof(struct btrfs_key_ptr) * nr; btrfs_set_key_blockptr(eb, (struct btrfs_key_ptr *)ptr, val); } static inline u64 btrfs_node_ptr_generation(struct extent_buffer *eb, int nr) { unsigned long ptr; ptr = offsetof(struct btrfs_node, ptrs) + sizeof(struct btrfs_key_ptr) * nr; return btrfs_key_generation(eb, (struct btrfs_key_ptr *)ptr); } static inline void btrfs_set_node_ptr_generation(struct extent_buffer *eb, int nr, u64 val) { unsigned long ptr; ptr = offsetof(struct btrfs_node, ptrs) + sizeof(struct btrfs_key_ptr) * nr; btrfs_set_key_generation(eb, (struct btrfs_key_ptr *)ptr, val); } static inline unsigned long btrfs_node_key_ptr_offset(int nr) { return offsetof(struct btrfs_node, ptrs) + sizeof(struct btrfs_key_ptr) * nr; } static inline void btrfs_node_key(struct extent_buffer *eb, struct btrfs_disk_key *disk_key, int nr) { unsigned long ptr; ptr = btrfs_node_key_ptr_offset(nr); read_eb_member(eb, (struct btrfs_key_ptr *)ptr, struct btrfs_key_ptr, key, disk_key); } static inline void btrfs_set_node_key(struct extent_buffer *eb, struct btrfs_disk_key *disk_key, int nr) { unsigned long ptr; ptr = btrfs_node_key_ptr_offset(nr); write_eb_member(eb, (struct btrfs_key_ptr *)ptr, struct btrfs_key_ptr, key, disk_key); } /* struct btrfs_item */ BTRFS_SETGET_FUNCS(item_offset, struct btrfs_item, offset, 32); BTRFS_SETGET_FUNCS(item_size, struct btrfs_item, size, 32); static inline unsigned long btrfs_item_nr_offset(int nr) { return offsetof(struct btrfs_leaf, items) + sizeof(struct btrfs_item) * nr; } static inline struct btrfs_item *btrfs_item_nr(int nr) { return (struct btrfs_item *)btrfs_item_nr_offset(nr); } static inline u32 btrfs_item_end(struct extent_buffer *eb, struct btrfs_item *item) { return btrfs_item_offset(eb, item) + btrfs_item_size(eb, item); } static inline u32 btrfs_item_end_nr(struct extent_buffer *eb, int nr) { return btrfs_item_end(eb, btrfs_item_nr(nr)); } static inline u32 btrfs_item_offset_nr(struct extent_buffer *eb, int nr) { return btrfs_item_offset(eb, btrfs_item_nr(nr)); } static inline u32 btrfs_item_size_nr(struct extent_buffer *eb, int nr) { return btrfs_item_size(eb, btrfs_item_nr(nr)); } static inline void btrfs_item_key(struct extent_buffer *eb, struct btrfs_disk_key *disk_key, int nr) { struct btrfs_item *item = btrfs_item_nr(nr); read_eb_member(eb, item, struct btrfs_item, key, disk_key); } static inline void btrfs_set_item_key(struct extent_buffer *eb, struct btrfs_disk_key *disk_key, int nr) { struct btrfs_item *item = btrfs_item_nr(nr); write_eb_member(eb, item, struct btrfs_item, key, disk_key); } BTRFS_SETGET_FUNCS(dir_log_end, struct btrfs_dir_log_item, end, 64); /* * struct btrfs_root_ref */ BTRFS_SETGET_FUNCS(root_ref_dirid, struct btrfs_root_ref, dirid, 64); BTRFS_SETGET_FUNCS(root_ref_sequence, struct btrfs_root_ref, sequence, 64); BTRFS_SETGET_FUNCS(root_ref_name_len, struct btrfs_root_ref, name_len, 16); BTRFS_SETGET_STACK_FUNCS(stack_root_ref_dirid, struct btrfs_root_ref, dirid, 64); BTRFS_SETGET_STACK_FUNCS(stack_root_ref_sequence, struct btrfs_root_ref, sequence, 64); BTRFS_SETGET_STACK_FUNCS(stack_root_ref_name_len, struct btrfs_root_ref, name_len, 16); /* struct btrfs_dir_item */ BTRFS_SETGET_FUNCS(dir_data_len, struct btrfs_dir_item, data_len, 16); BTRFS_SETGET_FUNCS(dir_type, struct btrfs_dir_item, type, 8); BTRFS_SETGET_FUNCS(dir_name_len, struct btrfs_dir_item, name_len, 16); BTRFS_SETGET_FUNCS(dir_transid, struct btrfs_dir_item, transid, 64); BTRFS_SETGET_STACK_FUNCS(stack_dir_name_len, struct btrfs_dir_item, name_len, 16); static inline void btrfs_dir_item_key(struct extent_buffer *eb, struct btrfs_dir_item *item, struct btrfs_disk_key *key) { read_eb_member(eb, item, struct btrfs_dir_item, location, key); } static inline void btrfs_set_dir_item_key(struct extent_buffer *eb, struct btrfs_dir_item *item, struct btrfs_disk_key *key) { write_eb_member(eb, item, struct btrfs_dir_item, location, key); } /* struct btrfs_free_space_header */ BTRFS_SETGET_FUNCS(free_space_entries, struct btrfs_free_space_header, num_entries, 64); BTRFS_SETGET_FUNCS(free_space_bitmaps, struct btrfs_free_space_header, num_bitmaps, 64); BTRFS_SETGET_FUNCS(free_space_generation, struct btrfs_free_space_header, generation, 64); static inline void btrfs_free_space_key(struct extent_buffer *eb, struct btrfs_free_space_header *h, struct btrfs_disk_key *key) { read_eb_member(eb, h, struct btrfs_free_space_header, location, key); } static inline void btrfs_set_free_space_key(struct extent_buffer *eb, struct btrfs_free_space_header *h, struct btrfs_disk_key *key) { write_eb_member(eb, h, struct btrfs_free_space_header, location, key); } /* struct btrfs_disk_key */ BTRFS_SETGET_STACK_FUNCS(disk_key_objectid, struct btrfs_disk_key, objectid, 64); BTRFS_SETGET_STACK_FUNCS(disk_key_offset, struct btrfs_disk_key, offset, 64); BTRFS_SETGET_STACK_FUNCS(disk_key_type, struct btrfs_disk_key, type, 8); static inline void btrfs_disk_key_to_cpu(struct btrfs_key *cpu, struct btrfs_disk_key *disk) { cpu->offset = le64_to_cpu(disk->offset); cpu->type = disk->type; cpu->objectid = le64_to_cpu(disk->objectid); } static inline void btrfs_cpu_key_to_disk(struct btrfs_disk_key *disk, struct btrfs_key *cpu) { disk->offset = cpu_to_le64(cpu->offset); disk->type = cpu->type; disk->objectid = cpu_to_le64(cpu->objectid); } static inline void btrfs_node_key_to_cpu(struct extent_buffer *eb, struct btrfs_key *key, int nr) { struct btrfs_disk_key disk_key; btrfs_node_key(eb, &disk_key, nr); btrfs_disk_key_to_cpu(key, &disk_key); } static inline void btrfs_item_key_to_cpu(struct extent_buffer *eb, struct btrfs_key *key, int nr) { struct btrfs_disk_key disk_key; btrfs_item_key(eb, &disk_key, nr); btrfs_disk_key_to_cpu(key, &disk_key); } static inline void btrfs_dir_item_key_to_cpu(struct extent_buffer *eb, struct btrfs_dir_item *item, struct btrfs_key *key) { struct btrfs_disk_key disk_key; btrfs_dir_item_key(eb, item, &disk_key); btrfs_disk_key_to_cpu(key, &disk_key); } static inline u8 btrfs_key_type(struct btrfs_key *key) { return key->type; } static inline void btrfs_set_key_type(struct btrfs_key *key, u8 val) { key->type = val; } /* struct btrfs_header */ BTRFS_SETGET_HEADER_FUNCS(header_bytenr, struct btrfs_header, bytenr, 64); BTRFS_SETGET_HEADER_FUNCS(header_generation, struct btrfs_header, generation, 64); BTRFS_SETGET_HEADER_FUNCS(header_owner, struct btrfs_header, owner, 64); BTRFS_SETGET_HEADER_FUNCS(header_nritems, struct btrfs_header, nritems, 32); BTRFS_SETGET_HEADER_FUNCS(header_flags, struct btrfs_header, flags, 64); BTRFS_SETGET_HEADER_FUNCS(header_level, struct btrfs_header, level, 8); BTRFS_SETGET_STACK_FUNCS(stack_header_bytenr, struct btrfs_header, bytenr, 64); BTRFS_SETGET_STACK_FUNCS(stack_header_nritems, struct btrfs_header, nritems, 32); BTRFS_SETGET_STACK_FUNCS(stack_header_owner, struct btrfs_header, owner, 64); BTRFS_SETGET_STACK_FUNCS(stack_header_generation, struct btrfs_header, generation, 64); static inline int btrfs_header_flag(struct extent_buffer *eb, u64 flag) { return (btrfs_header_flags(eb) & flag) == flag; } static inline int btrfs_set_header_flag(struct extent_buffer *eb, u64 flag) { u64 flags = btrfs_header_flags(eb); btrfs_set_header_flags(eb, flags | flag); return (flags & flag) == flag; } static inline int btrfs_clear_header_flag(struct extent_buffer *eb, u64 flag) { u64 flags = btrfs_header_flags(eb); btrfs_set_header_flags(eb, flags & ~flag); return (flags & flag) == flag; } static inline int btrfs_header_backref_rev(struct extent_buffer *eb) { u64 flags = btrfs_header_flags(eb); return flags >> BTRFS_BACKREF_REV_SHIFT; } static inline void btrfs_set_header_backref_rev(struct extent_buffer *eb, int rev) { u64 flags = btrfs_header_flags(eb); flags &= ~BTRFS_BACKREF_REV_MASK; flags |= (u64)rev << BTRFS_BACKREF_REV_SHIFT; btrfs_set_header_flags(eb, flags); } static inline unsigned long btrfs_header_fsid(void) { return offsetof(struct btrfs_header, fsid); } static inline unsigned long btrfs_header_chunk_tree_uuid(struct extent_buffer *eb) { return offsetof(struct btrfs_header, chunk_tree_uuid); } static inline u8 *btrfs_super_fsid(struct extent_buffer *eb) { unsigned long ptr = offsetof(struct btrfs_super_block, fsid); return (u8 *)ptr; } static inline u8 *btrfs_header_csum(struct extent_buffer *eb) { unsigned long ptr = offsetof(struct btrfs_header, csum); return (u8 *)ptr; } static inline struct btrfs_node *btrfs_buffer_node(struct extent_buffer *eb) { return NULL; } static inline struct btrfs_leaf *btrfs_buffer_leaf(struct extent_buffer *eb) { return NULL; } static inline struct btrfs_header *btrfs_buffer_header(struct extent_buffer *eb) { return NULL; } static inline int btrfs_is_leaf(struct extent_buffer *eb) { return (btrfs_header_level(eb) == 0); } /* struct btrfs_root_item */ BTRFS_SETGET_FUNCS(disk_root_generation, struct btrfs_root_item, generation, 64); BTRFS_SETGET_FUNCS(disk_root_refs, struct btrfs_root_item, refs, 32); BTRFS_SETGET_FUNCS(disk_root_bytenr, struct btrfs_root_item, bytenr, 64); BTRFS_SETGET_FUNCS(disk_root_level, struct btrfs_root_item, level, 8); BTRFS_SETGET_STACK_FUNCS(root_generation, struct btrfs_root_item, generation, 64); BTRFS_SETGET_STACK_FUNCS(root_bytenr, struct btrfs_root_item, bytenr, 64); BTRFS_SETGET_STACK_FUNCS(root_level, struct btrfs_root_item, level, 8); BTRFS_SETGET_STACK_FUNCS(root_dirid, struct btrfs_root_item, root_dirid, 64); BTRFS_SETGET_STACK_FUNCS(root_refs, struct btrfs_root_item, refs, 32); BTRFS_SETGET_STACK_FUNCS(root_flags, struct btrfs_root_item, flags, 64); BTRFS_SETGET_STACK_FUNCS(root_used, struct btrfs_root_item, bytes_used, 64); BTRFS_SETGET_STACK_FUNCS(root_limit, struct btrfs_root_item, byte_limit, 64); BTRFS_SETGET_STACK_FUNCS(root_last_snapshot, struct btrfs_root_item, last_snapshot, 64); BTRFS_SETGET_STACK_FUNCS(root_generation_v2, struct btrfs_root_item, generation_v2, 64); BTRFS_SETGET_STACK_FUNCS(root_ctransid, struct btrfs_root_item, ctransid, 64); BTRFS_SETGET_STACK_FUNCS(root_otransid, struct btrfs_root_item, otransid, 64); BTRFS_SETGET_STACK_FUNCS(root_stransid, struct btrfs_root_item, stransid, 64); BTRFS_SETGET_STACK_FUNCS(root_rtransid, struct btrfs_root_item, rtransid, 64); /* struct btrfs_root_backup */ BTRFS_SETGET_STACK_FUNCS(backup_tree_root, struct btrfs_root_backup, tree_root, 64); BTRFS_SETGET_STACK_FUNCS(backup_tree_root_gen, struct btrfs_root_backup, tree_root_gen, 64); BTRFS_SETGET_STACK_FUNCS(backup_tree_root_level, struct btrfs_root_backup, tree_root_level, 8); BTRFS_SETGET_STACK_FUNCS(backup_chunk_root, struct btrfs_root_backup, chunk_root, 64); BTRFS_SETGET_STACK_FUNCS(backup_chunk_root_gen, struct btrfs_root_backup, chunk_root_gen, 64); BTRFS_SETGET_STACK_FUNCS(backup_chunk_root_level, struct btrfs_root_backup, chunk_root_level, 8); BTRFS_SETGET_STACK_FUNCS(backup_extent_root, struct btrfs_root_backup, extent_root, 64); BTRFS_SETGET_STACK_FUNCS(backup_extent_root_gen, struct btrfs_root_backup, extent_root_gen, 64); BTRFS_SETGET_STACK_FUNCS(backup_extent_root_level, struct btrfs_root_backup, extent_root_level, 8); BTRFS_SETGET_STACK_FUNCS(backup_fs_root, struct btrfs_root_backup, fs_root, 64); BTRFS_SETGET_STACK_FUNCS(backup_fs_root_gen, struct btrfs_root_backup, fs_root_gen, 64); BTRFS_SETGET_STACK_FUNCS(backup_fs_root_level, struct btrfs_root_backup, fs_root_level, 8); BTRFS_SETGET_STACK_FUNCS(backup_dev_root, struct btrfs_root_backup, dev_root, 64); BTRFS_SETGET_STACK_FUNCS(backup_dev_root_gen, struct btrfs_root_backup, dev_root_gen, 64); BTRFS_SETGET_STACK_FUNCS(backup_dev_root_level, struct btrfs_root_backup, dev_root_level, 8); BTRFS_SETGET_STACK_FUNCS(backup_csum_root, struct btrfs_root_backup, csum_root, 64); BTRFS_SETGET_STACK_FUNCS(backup_csum_root_gen, struct btrfs_root_backup, csum_root_gen, 64); BTRFS_SETGET_STACK_FUNCS(backup_csum_root_level, struct btrfs_root_backup, csum_root_level, 8); BTRFS_SETGET_STACK_FUNCS(backup_total_bytes, struct btrfs_root_backup, total_bytes, 64); BTRFS_SETGET_STACK_FUNCS(backup_bytes_used, struct btrfs_root_backup, bytes_used, 64); BTRFS_SETGET_STACK_FUNCS(backup_num_devices, struct btrfs_root_backup, num_devices, 64); /* struct btrfs_super_block */ BTRFS_SETGET_STACK_FUNCS(super_bytenr, struct btrfs_super_block, bytenr, 64); BTRFS_SETGET_STACK_FUNCS(super_flags, struct btrfs_super_block, flags, 64); BTRFS_SETGET_STACK_FUNCS(super_generation, struct btrfs_super_block, generation, 64); BTRFS_SETGET_STACK_FUNCS(super_root, struct btrfs_super_block, root, 64); BTRFS_SETGET_STACK_FUNCS(super_sys_array_size, struct btrfs_super_block, sys_chunk_array_size, 32); BTRFS_SETGET_STACK_FUNCS(super_chunk_root_generation, struct btrfs_super_block, chunk_root_generation, 64); BTRFS_SETGET_STACK_FUNCS(super_root_level, struct btrfs_super_block, root_level, 8); BTRFS_SETGET_STACK_FUNCS(super_chunk_root, struct btrfs_super_block, chunk_root, 64); BTRFS_SETGET_STACK_FUNCS(super_chunk_root_level, struct btrfs_super_block, chunk_root_level, 8); BTRFS_SETGET_STACK_FUNCS(super_log_root, struct btrfs_super_block, log_root, 64); BTRFS_SETGET_STACK_FUNCS(super_log_root_transid, struct btrfs_super_block, log_root_transid, 64); BTRFS_SETGET_STACK_FUNCS(super_log_root_level, struct btrfs_super_block, log_root_level, 8); BTRFS_SETGET_STACK_FUNCS(super_total_bytes, struct btrfs_super_block, total_bytes, 64); BTRFS_SETGET_STACK_FUNCS(super_bytes_used, struct btrfs_super_block, bytes_used, 64); BTRFS_SETGET_STACK_FUNCS(super_sectorsize, struct btrfs_super_block, sectorsize, 32); BTRFS_SETGET_STACK_FUNCS(super_nodesize, struct btrfs_super_block, nodesize, 32); BTRFS_SETGET_STACK_FUNCS(super_leafsize, struct btrfs_super_block, leafsize, 32); BTRFS_SETGET_STACK_FUNCS(super_stripesize, struct btrfs_super_block, stripesize, 32); BTRFS_SETGET_STACK_FUNCS(super_root_dir, struct btrfs_super_block, root_dir_objectid, 64); BTRFS_SETGET_STACK_FUNCS(super_num_devices, struct btrfs_super_block, num_devices, 64); BTRFS_SETGET_STACK_FUNCS(super_compat_flags, struct btrfs_super_block, compat_flags, 64); BTRFS_SETGET_STACK_FUNCS(super_compat_ro_flags, struct btrfs_super_block, compat_ro_flags, 64); BTRFS_SETGET_STACK_FUNCS(super_incompat_flags, struct btrfs_super_block, incompat_flags, 64); BTRFS_SETGET_STACK_FUNCS(super_csum_type, struct btrfs_super_block, csum_type, 16); BTRFS_SETGET_STACK_FUNCS(super_cache_generation, struct btrfs_super_block, cache_generation, 64); BTRFS_SETGET_STACK_FUNCS(super_uuid_tree_generation, struct btrfs_super_block, uuid_tree_generation, 64); BTRFS_SETGET_STACK_FUNCS(super_magic, struct btrfs_super_block, magic, 64); static inline int btrfs_super_csum_size(struct btrfs_super_block *s) { int t = btrfs_super_csum_type(s); BUG_ON(t >= ARRAY_SIZE(btrfs_csum_sizes)); return btrfs_csum_sizes[t]; } static inline unsigned long btrfs_leaf_data(struct extent_buffer *l) { return offsetof(struct btrfs_leaf, items); } /* struct btrfs_file_extent_item */ BTRFS_SETGET_FUNCS(file_extent_type, struct btrfs_file_extent_item, type, 8); BTRFS_SETGET_STACK_FUNCS(stack_file_extent_type, struct btrfs_file_extent_item, type, 8); static inline unsigned long btrfs_file_extent_inline_start(struct btrfs_file_extent_item *e) { unsigned long offset = (unsigned long)e; offset += offsetof(struct btrfs_file_extent_item, disk_bytenr); return offset; } static inline u32 btrfs_file_extent_calc_inline_size(u32 datasize) { return offsetof(struct btrfs_file_extent_item, disk_bytenr) + datasize; } BTRFS_SETGET_FUNCS(file_extent_disk_bytenr, struct btrfs_file_extent_item, disk_bytenr, 64); BTRFS_SETGET_STACK_FUNCS(stack_file_extent_disk_bytenr, struct btrfs_file_extent_item, disk_bytenr, 64); BTRFS_SETGET_FUNCS(file_extent_generation, struct btrfs_file_extent_item, generation, 64); BTRFS_SETGET_STACK_FUNCS(stack_file_extent_generation, struct btrfs_file_extent_item, generation, 64); BTRFS_SETGET_FUNCS(file_extent_disk_num_bytes, struct btrfs_file_extent_item, disk_num_bytes, 64); BTRFS_SETGET_FUNCS(file_extent_offset, struct btrfs_file_extent_item, offset, 64); BTRFS_SETGET_STACK_FUNCS(stack_file_extent_offset, struct btrfs_file_extent_item, offset, 64); BTRFS_SETGET_FUNCS(file_extent_num_bytes, struct btrfs_file_extent_item, num_bytes, 64); BTRFS_SETGET_STACK_FUNCS(stack_file_extent_num_bytes, struct btrfs_file_extent_item, num_bytes, 64); BTRFS_SETGET_FUNCS(file_extent_ram_bytes, struct btrfs_file_extent_item, ram_bytes, 64); BTRFS_SETGET_STACK_FUNCS(stack_file_extent_ram_bytes, struct btrfs_file_extent_item, ram_bytes, 64); BTRFS_SETGET_FUNCS(file_extent_compression, struct btrfs_file_extent_item, compression, 8); BTRFS_SETGET_STACK_FUNCS(stack_file_extent_compression, struct btrfs_file_extent_item, compression, 8); BTRFS_SETGET_FUNCS(file_extent_encryption, struct btrfs_file_extent_item, encryption, 8); BTRFS_SETGET_FUNCS(file_extent_other_encoding, struct btrfs_file_extent_item, other_encoding, 16); /* btrfs_qgroup_status_item */ BTRFS_SETGET_FUNCS(qgroup_status_version, struct btrfs_qgroup_status_item, version, 64); BTRFS_SETGET_FUNCS(qgroup_status_generation, struct btrfs_qgroup_status_item, generation, 64); BTRFS_SETGET_FUNCS(qgroup_status_flags, struct btrfs_qgroup_status_item, flags, 64); BTRFS_SETGET_FUNCS(qgroup_status_scan, struct btrfs_qgroup_status_item, scan, 64); /* btrfs_qgroup_info_item */ BTRFS_SETGET_FUNCS(qgroup_info_generation, struct btrfs_qgroup_info_item, generation, 64); BTRFS_SETGET_FUNCS(qgroup_info_referenced, struct btrfs_qgroup_info_item, referenced, 64); BTRFS_SETGET_FUNCS(qgroup_info_referenced_compressed, struct btrfs_qgroup_info_item, referenced_compressed, 64); BTRFS_SETGET_FUNCS(qgroup_info_exclusive, struct btrfs_qgroup_info_item, exclusive, 64); BTRFS_SETGET_FUNCS(qgroup_info_exclusive_compressed, struct btrfs_qgroup_info_item, exclusive_compressed, 64); BTRFS_SETGET_STACK_FUNCS(stack_qgroup_info_generation, struct btrfs_qgroup_info_item, generation, 64); BTRFS_SETGET_STACK_FUNCS(stack_qgroup_info_referenced, struct btrfs_qgroup_info_item, referenced, 64); BTRFS_SETGET_STACK_FUNCS(stack_qgroup_info_referenced_compressed, struct btrfs_qgroup_info_item, referenced_compressed, 64); BTRFS_SETGET_STACK_FUNCS(stack_qgroup_info_exclusive, struct btrfs_qgroup_info_item, exclusive, 64); BTRFS_SETGET_STACK_FUNCS(stack_qgroup_info_exclusive_compressed, struct btrfs_qgroup_info_item, exclusive_compressed, 64); /* btrfs_qgroup_limit_item */ BTRFS_SETGET_FUNCS(qgroup_limit_flags, struct btrfs_qgroup_limit_item, flags, 64); BTRFS_SETGET_FUNCS(qgroup_limit_max_referenced, struct btrfs_qgroup_limit_item, max_referenced, 64); BTRFS_SETGET_FUNCS(qgroup_limit_max_exclusive, struct btrfs_qgroup_limit_item, max_exclusive, 64); BTRFS_SETGET_FUNCS(qgroup_limit_rsv_referenced, struct btrfs_qgroup_limit_item, rsv_referenced, 64); BTRFS_SETGET_FUNCS(qgroup_limit_rsv_exclusive, struct btrfs_qgroup_limit_item, rsv_exclusive, 64); BTRFS_SETGET_STACK_FUNCS(stack_qgroup_limit_flags, struct btrfs_qgroup_limit_item, flags, 64); BTRFS_SETGET_STACK_FUNCS(stack_qgroup_limit_max_referenced, struct btrfs_qgroup_limit_item, max_referenced, 64); BTRFS_SETGET_STACK_FUNCS(stack_qgroup_limit_max_exclusive, struct btrfs_qgroup_limit_item, max_exclusive, 64); BTRFS_SETGET_STACK_FUNCS(stack_qgroup_limit_rsv_referenced, struct btrfs_qgroup_limit_item, rsv_referenced, 64); BTRFS_SETGET_STACK_FUNCS(stack_qgroup_limit_rsv_exclusive, struct btrfs_qgroup_limit_item, rsv_exclusive, 64); /* * this returns the number of bytes used by the item on disk, minus the * size of any extent headers. If a file is compressed on disk, this is * the compressed size */ static inline u32 btrfs_file_extent_inline_item_len(struct extent_buffer *eb, struct btrfs_item *e) { unsigned long offset; offset = offsetof(struct btrfs_file_extent_item, disk_bytenr); return btrfs_item_size(eb, e) - offset; } /* this returns the number of file bytes represented by the inline item. * If an item is compressed, this is the uncompressed size */ static inline u32 btrfs_file_extent_inline_len(struct extent_buffer *eb, int slot, struct btrfs_file_extent_item *fi) { /* * return the space used on disk if this item isn't * compressed or encoded */ if (btrfs_file_extent_compression(eb, fi) == 0 && btrfs_file_extent_encryption(eb, fi) == 0 && btrfs_file_extent_other_encoding(eb, fi) == 0) { return btrfs_file_extent_inline_item_len(eb, btrfs_item_nr(slot)); } /* otherwise use the ram bytes field */ return btrfs_file_extent_ram_bytes(eb, fi); } static inline u32 btrfs_level_size(struct btrfs_root *root, int level) { if (level == 0) return root->leafsize; return root->nodesize; } static inline int btrfs_fs_incompat(struct btrfs_fs_info *fs_info, u64 flag) { struct btrfs_super_block *disk_super; disk_super = fs_info->super_copy; return !!(btrfs_super_incompat_flags(disk_super) & flag); } /* helper function to cast into the data area of the leaf. */ #define btrfs_item_ptr(leaf, slot, type) \ ((type *)(btrfs_leaf_data(leaf) + \ btrfs_item_offset_nr(leaf, slot))) #define btrfs_item_ptr_offset(leaf, slot) \ ((unsigned long)(btrfs_leaf_data(leaf) + \ btrfs_item_offset_nr(leaf, slot))) /* extent-tree.c */ int btrfs_reserve_extent(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 num_bytes, u64 empty_size, u64 hint_byte, u64 search_end, struct btrfs_key *ins, int data); int btrfs_fix_block_accounting(struct btrfs_trans_handle *trans, struct btrfs_root *root); void btrfs_pin_extent(struct btrfs_fs_info *fs_info, u64 bytenr, u64 num_bytes); void btrfs_unpin_extent(struct btrfs_fs_info *fs_info, u64 bytenr, u64 num_bytes); int btrfs_extent_post_op(struct btrfs_trans_handle *trans, struct btrfs_root *root); struct btrfs_block_group_cache *btrfs_lookup_block_group(struct btrfs_fs_info *info, u64 bytenr); struct btrfs_block_group_cache *btrfs_lookup_first_block_group(struct btrfs_fs_info *info, u64 bytenr); struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, u32 blocksize, u64 root_objectid, struct btrfs_disk_key *key, int level, u64 hint, u64 empty_size); int btrfs_alloc_extent(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 num_bytes, u64 parent, u64 root_objectid, u64 ref_generation, u64 owner, u64 empty_size, u64 hint_byte, u64 search_end, struct btrfs_key *ins, int data); int btrfs_lookup_extent_info(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 bytenr, u64 offset, int metadata, u64 *refs, u64 *flags); int btrfs_set_block_flags(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 bytenr, int level, u64 flags); int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct extent_buffer *buf, int record_parent); int btrfs_dec_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct extent_buffer *buf, int record_parent); int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 bytenr, u64 num_bytes, u64 parent, u64 root_objectid, u64 owner, u64 offset); int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct extent_io_tree *unpin); int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 bytenr, u64 num_bytes, u64 parent, u64 root_objectid, u64 ref_generation, u64 owner_objectid); int btrfs_update_extent_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 bytenr, u64 orig_parent, u64 parent, u64 root_objectid, u64 ref_generation, u64 owner_objectid); int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans, struct btrfs_root *root); int btrfs_free_block_groups(struct btrfs_fs_info *info); int btrfs_read_block_groups(struct btrfs_root *root); struct btrfs_block_group_cache * btrfs_add_block_group(struct btrfs_fs_info *fs_info, u64 bytes_used, u64 type, u64 chunk_objectid, u64 chunk_offset, u64 size); int btrfs_make_block_group(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 bytes_used, u64 type, u64 chunk_objectid, u64 chunk_offset, u64 size); int btrfs_make_block_groups(struct btrfs_trans_handle *trans, struct btrfs_root *root); int btrfs_update_block_group(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 bytenr, u64 num, int alloc, int mark_free); int btrfs_record_file_extent(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 objectid, struct btrfs_inode_item *inode, u64 file_pos, u64 disk_bytenr, u64 num_bytes); /* ctree.c */ int btrfs_comp_cpu_keys(struct btrfs_key *k1, struct btrfs_key *k2); int btrfs_del_ptr(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, int level, int slot); enum btrfs_tree_block_status btrfs_check_node(struct btrfs_root *root, struct btrfs_disk_key *parent_key, struct extent_buffer *buf); enum btrfs_tree_block_status btrfs_check_leaf(struct btrfs_root *root, struct btrfs_disk_key *parent_key, struct extent_buffer *buf); void reada_for_search(struct btrfs_root *root, struct btrfs_path *path, int level, int slot, u64 objectid); struct extent_buffer *read_node_slot(struct btrfs_root *root, struct extent_buffer *parent, int slot); int btrfs_previous_item(struct btrfs_root *root, struct btrfs_path *path, u64 min_objectid, int type); int btrfs_previous_extent_item(struct btrfs_root *root, struct btrfs_path *path, u64 min_objectid); int btrfs_cow_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct extent_buffer *buf, struct extent_buffer *parent, int parent_slot, struct extent_buffer **cow_ret); int __btrfs_cow_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct extent_buffer *buf, struct extent_buffer *parent, int parent_slot, struct extent_buffer **cow_ret, u64 search_start, u64 empty_size); int btrfs_copy_root(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct extent_buffer *buf, struct extent_buffer **cow_ret, u64 new_root_objectid); int btrfs_extend_item(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, u32 data_size); int btrfs_truncate_item(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, u32 new_size, int from_end); int btrfs_split_item(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, struct btrfs_key *new_key, unsigned long split_offset); int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_key *key, struct btrfs_path *p, int ins_len, int cow); int btrfs_find_item(struct btrfs_root *fs_root, struct btrfs_path *found_path, u64 iobjectid, u64 ioff, u8 key_type, struct btrfs_key *found_key); void btrfs_release_path(struct btrfs_path *p); void add_root_to_dirty_list(struct btrfs_root *root); struct btrfs_path *btrfs_alloc_path(void); void btrfs_free_path(struct btrfs_path *p); void btrfs_init_path(struct btrfs_path *p); int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, int slot, int nr); static inline int btrfs_del_item(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path) { return btrfs_del_items(trans, root, path, path->slots[0], 1); } int btrfs_insert_item(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_key *key, void *data, u32 data_size); int btrfs_insert_empty_items(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, struct btrfs_key *cpu_key, u32 *data_size, int nr); static inline int btrfs_insert_empty_item(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, struct btrfs_key *key, u32 data_size) { return btrfs_insert_empty_items(trans, root, path, key, &data_size, 1); } int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path); static inline int btrfs_next_item(struct btrfs_root *root, struct btrfs_path *p) { ++p->slots[0]; if (p->slots[0] >= btrfs_header_nritems(p->nodes[0])) return btrfs_next_leaf(root, p); return 0; } int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path); int btrfs_leaf_free_space(struct btrfs_root *root, struct extent_buffer *leaf); void btrfs_fixup_low_keys(struct btrfs_root *root, struct btrfs_path *path, struct btrfs_disk_key *key, int level); int btrfs_set_item_key_safe(struct btrfs_root *root, struct btrfs_path *path, struct btrfs_key *new_key); void btrfs_set_item_key_unsafe(struct btrfs_root *root, struct btrfs_path *path, struct btrfs_key *new_key); /* root-item.c */ int btrfs_add_root_ref(struct btrfs_trans_handle *trans, struct btrfs_root *tree_root, u64 root_id, u8 type, u64 ref_id, u64 dirid, u64 sequence, const char *name, int name_len); int btrfs_insert_root(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_key *key, struct btrfs_root_item *item); int btrfs_update_root(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_key *key, struct btrfs_root_item *item); int btrfs_find_last_root(struct btrfs_root *root, u64 objectid, struct btrfs_root_item *item, struct btrfs_key *key); /* dir-item.c */ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root *root, const char *name, int name_len, u64 dir, struct btrfs_key *location, u8 type, u64 index); struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, u64 dir, const char *name, int name_len, int mod); struct btrfs_dir_item *btrfs_lookup_dir_index(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, u64 dir, const char *name, int name_len, u64 index, int mod); int btrfs_delete_one_dir_name(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, struct btrfs_dir_item *di); int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans, struct btrfs_root *root, const char *name, u16 name_len, const void *data, u16 data_len, u64 dir); /* inode-map.c */ int btrfs_find_free_objectid(struct btrfs_trans_handle *trans, struct btrfs_root *fs_root, u64 dirid, u64 *objectid); /* inode-item.c */ int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, const char *name, int name_len, u64 inode_objectid, u64 ref_objectid, u64 index); int btrfs_insert_inode(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 objectid, struct btrfs_inode_item *inode_item); int btrfs_lookup_inode(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, struct btrfs_key *location, int mod); /* file-item.c */ int btrfs_del_csums(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 bytenr, u64 len); int btrfs_insert_file_extent(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 objectid, u64 pos, u64 offset, u64 disk_num_bytes, u64 num_bytes); int btrfs_insert_inline_extent(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 objectid, u64 offset, char *buffer, size_t size); int btrfs_csum_file_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 alloc_end, u64 bytenr, char *data, size_t len); int btrfs_csum_truncate(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, u64 isize); /* uuid-tree.c */ int btrfs_lookup_uuid_subvol_item(int fd, const u8 *uuid, u64 *subvol_id); int btrfs_lookup_uuid_received_subvol_item(int fd, const u8 *uuid, u64 *subvol_id); static inline int is_fstree(u64 rootid) { if (rootid == BTRFS_FS_TREE_OBJECTID || (signed long long)rootid >= (signed long long)BTRFS_FIRST_FREE_OBJECTID) return 1; return 0; } #endif partclone-0.2.86/src/btrfs/dir-item.c000066400000000000000000000235331262102574200173720ustar00rootroot00000000000000/* * Copyright (C) 2007 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. */ #include #include "ctree.h" #include "disk-io.h" #include "hash.h" #include "transaction.h" static struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_root *root, struct btrfs_path *path, const char *name, int name_len); static struct btrfs_dir_item *insert_with_overflow(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, struct btrfs_key *cpu_key, u32 data_size, const char *name, int name_len) { int ret; char *ptr; struct btrfs_item *item; struct extent_buffer *leaf; ret = btrfs_insert_empty_item(trans, root, path, cpu_key, data_size); if (ret == -EEXIST) { struct btrfs_dir_item *di; di = btrfs_match_dir_item_name(root, path, name, name_len); if (di) return ERR_PTR(-EEXIST); ret = btrfs_extend_item(trans, root, path, data_size); WARN_ON(ret > 0); } if (ret < 0) return ERR_PTR(ret); WARN_ON(ret > 0); leaf = path->nodes[0]; item = btrfs_item_nr(path->slots[0]); ptr = btrfs_item_ptr(leaf, path->slots[0], char); BUG_ON(data_size > btrfs_item_size(leaf, item)); ptr += btrfs_item_size(leaf, item) - data_size; return (struct btrfs_dir_item *)ptr; } int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans, struct btrfs_root *root, const char *name, u16 name_len, const void *data, u16 data_len, u64 dir) { int ret = 0; struct btrfs_path *path; struct btrfs_dir_item *dir_item; unsigned long name_ptr, data_ptr; struct btrfs_key key, location; struct btrfs_disk_key disk_key; struct extent_buffer *leaf; u32 data_size; key.objectid = dir; btrfs_set_key_type(&key, BTRFS_XATTR_ITEM_KEY); key.offset = btrfs_name_hash(name, name_len); path = btrfs_alloc_path(); if (!path) return -ENOMEM; data_size = sizeof(*dir_item) + name_len + data_len; dir_item = insert_with_overflow(trans, root, path, &key, data_size, name, name_len); /* * FIXME: at some point we should handle xattr's that are larger than * what we can fit in our leaf. We set location to NULL b/c we arent * pointing at anything else, that will change if we store the xattr * data in a separate inode. */ BUG_ON(IS_ERR(dir_item)); memset(&location, 0, sizeof(location)); leaf = path->nodes[0]; btrfs_cpu_key_to_disk(&disk_key, &location); btrfs_set_dir_item_key(leaf, dir_item, &disk_key); btrfs_set_dir_type(leaf, dir_item, BTRFS_FT_XATTR); btrfs_set_dir_name_len(leaf, dir_item, name_len); btrfs_set_dir_data_len(leaf, dir_item, data_len); name_ptr = (unsigned long)(dir_item + 1); data_ptr = (unsigned long)((char *)name_ptr + name_len); write_extent_buffer(leaf, name, name_ptr, name_len); write_extent_buffer(leaf, data, data_ptr, data_len); btrfs_mark_buffer_dirty(path->nodes[0]); btrfs_free_path(path); return ret; } int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root *root, const char *name, int name_len, u64 dir, struct btrfs_key *location, u8 type, u64 index) { int ret = 0; int ret2 = 0; struct btrfs_path *path; struct btrfs_dir_item *dir_item; struct extent_buffer *leaf; unsigned long name_ptr; struct btrfs_key key; struct btrfs_disk_key disk_key; u32 data_size; key.objectid = dir; btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY); key.offset = btrfs_name_hash(name, name_len); path = btrfs_alloc_path(); if (!path) return -ENOMEM; data_size = sizeof(*dir_item) + name_len; dir_item = insert_with_overflow(trans, root, path, &key, data_size, name, name_len); if (IS_ERR(dir_item)) { ret = PTR_ERR(dir_item); goto out; } leaf = path->nodes[0]; btrfs_cpu_key_to_disk(&disk_key, location); btrfs_set_dir_item_key(leaf, dir_item, &disk_key); btrfs_set_dir_type(leaf, dir_item, type); btrfs_set_dir_data_len(leaf, dir_item, 0); btrfs_set_dir_name_len(leaf, dir_item, name_len); name_ptr = (unsigned long)(dir_item + 1); write_extent_buffer(leaf, name, name_ptr, name_len); btrfs_mark_buffer_dirty(leaf); /* FIXME, use some real flag for selecting the extra index */ if (root == root->fs_info->tree_root) { ret = 0; goto out; } btrfs_release_path(path); btrfs_set_key_type(&key, BTRFS_DIR_INDEX_KEY); key.offset = index; dir_item = insert_with_overflow(trans, root, path, &key, data_size, name, name_len); if (IS_ERR(dir_item)) { ret2 = PTR_ERR(dir_item); goto out; } leaf = path->nodes[0]; btrfs_cpu_key_to_disk(&disk_key, location); btrfs_set_dir_item_key(leaf, dir_item, &disk_key); btrfs_set_dir_type(leaf, dir_item, type); btrfs_set_dir_data_len(leaf, dir_item, 0); btrfs_set_dir_name_len(leaf, dir_item, name_len); name_ptr = (unsigned long)(dir_item + 1); write_extent_buffer(leaf, name, name_ptr, name_len); btrfs_mark_buffer_dirty(leaf); out: btrfs_free_path(path); if (ret) return ret; if (ret2) return ret2; return 0; } struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, u64 dir, const char *name, int name_len, int mod) { int ret; struct btrfs_key key; int ins_len = mod < 0 ? -1 : 0; int cow = mod != 0; struct btrfs_key found_key; struct extent_buffer *leaf; key.objectid = dir; btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY); key.offset = btrfs_name_hash(name, name_len); ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow); if (ret < 0) return ERR_PTR(ret); if (ret > 0) { if (path->slots[0] == 0) return NULL; path->slots[0]--; } leaf = path->nodes[0]; btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); if (found_key.objectid != dir || btrfs_key_type(&found_key) != BTRFS_DIR_ITEM_KEY || found_key.offset != key.offset) return NULL; return btrfs_match_dir_item_name(root, path, name, name_len); } struct btrfs_dir_item *btrfs_lookup_dir_index(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, u64 dir, const char *name, int name_len, u64 index, int mod) { int ret; struct btrfs_key key; int ins_len = mod < 0 ? -1 : 0; int cow = mod != 0; key.objectid = dir; key.type = BTRFS_DIR_INDEX_KEY; key.offset = index; ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow); if (ret < 0) return ERR_PTR(ret); if (ret > 0) return ERR_PTR(-ENOENT); return btrfs_match_dir_item_name(root, path, name, name_len); } /* * given a pointer into a directory item, delete it. This * handles items that have more than one entry in them. */ int btrfs_delete_one_dir_name(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, struct btrfs_dir_item *di) { struct extent_buffer *leaf; u32 sub_item_len; u32 item_len; int ret = 0; leaf = path->nodes[0]; sub_item_len = sizeof(*di) + btrfs_dir_name_len(leaf, di) + btrfs_dir_data_len(leaf, di); item_len = btrfs_item_size_nr(leaf, path->slots[0]); if (sub_item_len == item_len) { ret = btrfs_del_item(trans, root, path); } else { unsigned long ptr = (unsigned long)di; unsigned long start; start = btrfs_item_ptr_offset(leaf, path->slots[0]); memmove_extent_buffer(leaf, ptr, ptr + sub_item_len, item_len - (ptr + sub_item_len - start)); btrfs_truncate_item(trans, root, path, item_len - sub_item_len, 1); } return ret; } int verify_dir_item(struct btrfs_root *root, struct extent_buffer *leaf, struct btrfs_dir_item *dir_item) { u16 namelen = BTRFS_NAME_LEN; u8 type = btrfs_dir_type(leaf, dir_item); if (type >= BTRFS_FT_MAX) { fprintf(stderr, "invalid dir item type: %d", (int)type); return 1; } if (type == BTRFS_FT_XATTR) namelen = XATTR_NAME_MAX; if (btrfs_dir_name_len(leaf, dir_item) > namelen) { fprintf(stderr, "invalid dir item name len: %u", (unsigned)btrfs_dir_data_len(leaf, dir_item)); return 1; } /* BTRFS_MAX_XATTR_SIZE is the same for all dir items */ if ((btrfs_dir_data_len(leaf, dir_item) + btrfs_dir_name_len(leaf, dir_item)) > BTRFS_MAX_XATTR_SIZE(root)) { fprintf(stderr, "invalid dir item name + data len: %u + %u", (unsigned)btrfs_dir_name_len(leaf, dir_item), (unsigned)btrfs_dir_data_len(leaf, dir_item)); return 1; } return 0; } static struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_root *root, struct btrfs_path *path, const char *name, int name_len) { struct btrfs_dir_item *dir_item; unsigned long name_ptr; u32 total_len; u32 cur = 0; u32 this_len; struct extent_buffer *leaf; leaf = path->nodes[0]; dir_item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_dir_item); total_len = btrfs_item_size_nr(leaf, path->slots[0]); if (verify_dir_item(root, leaf, dir_item)) return NULL; while(cur < total_len) { this_len = sizeof(*dir_item) + btrfs_dir_name_len(leaf, dir_item) + btrfs_dir_data_len(leaf, dir_item); if (this_len > (total_len - cur)) { fprintf(stderr, "invalid dir item size\n"); return NULL; } name_ptr = (unsigned long)(dir_item + 1); if (btrfs_dir_name_len(leaf, dir_item) == name_len && memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0) return dir_item; cur += this_len; dir_item = (struct btrfs_dir_item *)((char *)dir_item + this_len); } return NULL; } partclone-0.2.86/src/btrfs/disk-io.c000066400000000000000000001134701262102574200172170ustar00rootroot00000000000000/* * Copyright (C) 2007 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. */ #define _XOPEN_SOURCE 600 #define __USE_XOPEN2K #define _GNU_SOURCE 1 #include #include #include #include #include #include #include "kerncompat.h" #include "radix-tree.h" #include "ctree.h" #include "disk-io.h" #include "volumes.h" #include "transaction.h" #include "crc32c.h" #include "utils.h" #include "print-tree.h" #include "rbtree-utils.h" static int check_tree_block(struct btrfs_root *root, struct extent_buffer *buf) { struct btrfs_fs_devices *fs_devices; int ret = 1; if (buf->start != btrfs_header_bytenr(buf)) { printk("Check tree block failed, want=%Lu, have=%Lu\n", buf->start, btrfs_header_bytenr(buf)); return ret; } fs_devices = root->fs_info->fs_devices; while (fs_devices) { if (!memcmp_extent_buffer(buf, fs_devices->fsid, btrfs_header_fsid(), BTRFS_FSID_SIZE)) { ret = 0; break; } fs_devices = fs_devices->seed; } return ret; } u32 btrfs_csum_data(struct btrfs_root *root, char *data, u32 seed, size_t len) { return crc32c(seed, data, len); } void btrfs_csum_final(u32 crc, char *result) { *(__le32 *)result = ~cpu_to_le32(crc); } static int __csum_tree_block_size(struct extent_buffer *buf, u16 csum_size, int verify, int silent) { char *result; u32 len; u32 crc = ~(u32)0; result = malloc(csum_size * sizeof(char)); if (!result) return 1; len = buf->len - BTRFS_CSUM_SIZE; crc = crc32c(crc, buf->data + BTRFS_CSUM_SIZE, len); btrfs_csum_final(crc, result); if (verify) { if (memcmp_extent_buffer(buf, result, 0, csum_size)) { if (!silent) printk("checksum verify failed on %llu found %08X wanted %08X\n", (unsigned long long)buf->start, *((u32 *)result), *((u32*)(char *)buf->data)); free(result); return 1; } } else { write_extent_buffer(buf, result, 0, csum_size); } free(result); return 0; } int csum_tree_block_size(struct extent_buffer *buf, u16 csum_size, int verify) { return __csum_tree_block_size(buf, csum_size, verify, 0); } int verify_tree_block_csum_silent(struct extent_buffer *buf, u16 csum_size) { return __csum_tree_block_size(buf, csum_size, 1, 1); } int csum_tree_block(struct btrfs_root *root, struct extent_buffer *buf, int verify) { u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy); return csum_tree_block_size(buf, csum_size, verify); } struct extent_buffer *btrfs_find_tree_block(struct btrfs_root *root, u64 bytenr, u32 blocksize) { return find_extent_buffer(&root->fs_info->extent_cache, bytenr, blocksize); } struct extent_buffer *btrfs_find_create_tree_block(struct btrfs_root *root, u64 bytenr, u32 blocksize) { return alloc_extent_buffer(&root->fs_info->extent_cache, bytenr, blocksize); } void readahead_tree_block(struct btrfs_root *root, u64 bytenr, u32 blocksize, u64 parent_transid) { struct extent_buffer *eb; u64 length; struct btrfs_multi_bio *multi = NULL; struct btrfs_device *device; eb = btrfs_find_tree_block(root, bytenr, blocksize); if (!(eb && btrfs_buffer_uptodate(eb, parent_transid)) && !btrfs_map_block(&root->fs_info->mapping_tree, READ, bytenr, &length, &multi, 0, NULL)) { device = multi->stripes[0].dev; device->total_ios++; blocksize = min(blocksize, (u32)(64 * 1024)); readahead(device->fd, multi->stripes[0].physical, blocksize); } free_extent_buffer(eb); kfree(multi); } static int verify_parent_transid(struct extent_io_tree *io_tree, struct extent_buffer *eb, u64 parent_transid, int ignore) { int ret; if (!parent_transid || btrfs_header_generation(eb) == parent_transid) return 0; if (extent_buffer_uptodate(eb) && btrfs_header_generation(eb) == parent_transid) { ret = 0; goto out; } printk("parent transid verify failed on %llu wanted %llu found %llu\n", (unsigned long long)eb->start, (unsigned long long)parent_transid, (unsigned long long)btrfs_header_generation(eb)); if (ignore) { eb->flags |= EXTENT_BAD_TRANSID; printk("Ignoring transid failure\n"); return 0; } ret = 1; out: clear_extent_buffer_uptodate(io_tree, eb); return ret; } int read_whole_eb(struct btrfs_fs_info *info, struct extent_buffer *eb, int mirror) { unsigned long offset = 0; struct btrfs_multi_bio *multi = NULL; struct btrfs_device *device; int ret = 0; u64 read_len; unsigned long bytes_left = eb->len; while (bytes_left) { read_len = bytes_left; device = NULL; if (!info->on_restoring && eb->start != BTRFS_SUPER_INFO_OFFSET) { ret = btrfs_map_block(&info->mapping_tree, READ, eb->start + offset, &read_len, &multi, mirror, NULL); if (ret) { printk("Couldn't map the block %Lu\n", eb->start + offset); kfree(multi); return -EIO; } device = multi->stripes[0].dev; if (device->fd == 0) { kfree(multi); return -EIO; } eb->fd = device->fd; device->total_ios++; eb->dev_bytenr = multi->stripes[0].physical; kfree(multi); multi = NULL; } else { /* special case for restore metadump */ list_for_each_entry(device, &info->fs_devices->devices, dev_list) { if (device->devid == 1) break; } eb->fd = device->fd; eb->dev_bytenr = eb->start; device->total_ios++; } if (read_len > bytes_left) read_len = bytes_left; ret = read_extent_from_disk(eb, offset, read_len); if (ret) return -EIO; offset += read_len; bytes_left -= read_len; } return 0; } struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr, u32 blocksize, u64 parent_transid) { int ret; struct extent_buffer *eb; u64 best_transid = 0; int mirror_num = 0; int good_mirror = 0; int num_copies; int ignore = 0; eb = btrfs_find_create_tree_block(root, bytenr, blocksize); if (!eb) return NULL; if (btrfs_buffer_uptodate(eb, parent_transid)) return eb; while (1) { ret = read_whole_eb(root->fs_info, eb, mirror_num); if (ret == 0 && check_tree_block(root, eb) == 0 && csum_tree_block(root, eb, 1) == 0 && verify_parent_transid(eb->tree, eb, parent_transid, ignore) == 0) { if (eb->flags & EXTENT_BAD_TRANSID && list_empty(&eb->recow)) { list_add_tail(&eb->recow, &root->fs_info->recow_ebs); eb->refs++; } btrfs_set_buffer_uptodate(eb); return eb; } if (ignore) { if (check_tree_block(root, eb)) printk("read block failed check_tree_block\n"); else printk("Csum didn't match\n"); break; } num_copies = btrfs_num_copies(&root->fs_info->mapping_tree, eb->start, eb->len); if (num_copies == 1) { ignore = 1; continue; } if (btrfs_header_generation(eb) > best_transid && mirror_num) { best_transid = btrfs_header_generation(eb); good_mirror = mirror_num; } mirror_num++; if (mirror_num > num_copies) { mirror_num = good_mirror; ignore = 1; continue; } } free_extent_buffer(eb); return NULL; } int write_and_map_eb(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct extent_buffer *eb) { int ret; int dev_nr; u64 length; u64 *raid_map = NULL; struct btrfs_multi_bio *multi = NULL; dev_nr = 0; length = eb->len; ret = btrfs_map_block(&root->fs_info->mapping_tree, WRITE, eb->start, &length, &multi, 0, &raid_map); if (raid_map) { ret = write_raid56_with_parity(root->fs_info, eb, multi, length, raid_map); BUG_ON(ret); } else while (dev_nr < multi->num_stripes) { BUG_ON(ret); eb->fd = multi->stripes[dev_nr].dev->fd; eb->dev_bytenr = multi->stripes[dev_nr].physical; multi->stripes[dev_nr].dev->total_ios++; dev_nr++; ret = write_extent_to_disk(eb); BUG_ON(ret); } kfree(multi); return 0; } static int write_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct extent_buffer *eb) { if (check_tree_block(root, eb)) BUG(); if (!btrfs_buffer_uptodate(eb, trans->transid)) BUG(); btrfs_set_header_flag(eb, BTRFS_HEADER_FLAG_WRITTEN); csum_tree_block(root, eb, 0); return write_and_map_eb(trans, root, eb); } int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize, u32 stripesize, struct btrfs_root *root, struct btrfs_fs_info *fs_info, u64 objectid) { root->node = NULL; root->commit_root = NULL; root->sectorsize = sectorsize; root->nodesize = nodesize; root->leafsize = leafsize; root->stripesize = stripesize; root->ref_cows = 0; root->track_dirty = 0; root->fs_info = fs_info; root->objectid = objectid; root->last_trans = 0; root->highest_inode = 0; root->last_inode_alloc = 0; INIT_LIST_HEAD(&root->dirty_list); memset(&root->root_key, 0, sizeof(root->root_key)); memset(&root->root_item, 0, sizeof(root->root_item)); root->root_key.objectid = objectid; return 0; } static int update_cowonly_root(struct btrfs_trans_handle *trans, struct btrfs_root *root) { int ret; u64 old_root_bytenr; struct btrfs_root *tree_root = root->fs_info->tree_root; btrfs_write_dirty_block_groups(trans, root); while(1) { old_root_bytenr = btrfs_root_bytenr(&root->root_item); if (old_root_bytenr == root->node->start) break; btrfs_set_root_bytenr(&root->root_item, root->node->start); btrfs_set_root_generation(&root->root_item, trans->transid); root->root_item.level = btrfs_header_level(root->node); ret = btrfs_update_root(trans, tree_root, &root->root_key, &root->root_item); BUG_ON(ret); btrfs_write_dirty_block_groups(trans, root); } return 0; } static int commit_tree_roots(struct btrfs_trans_handle *trans, struct btrfs_fs_info *fs_info) { struct btrfs_root *root; struct list_head *next; struct extent_buffer *eb; int ret; if (fs_info->readonly) return 0; eb = fs_info->tree_root->node; extent_buffer_get(eb); ret = btrfs_cow_block(trans, fs_info->tree_root, eb, NULL, 0, &eb); free_extent_buffer(eb); if (ret) return ret; while(!list_empty(&fs_info->dirty_cowonly_roots)) { next = fs_info->dirty_cowonly_roots.next; list_del_init(next); root = list_entry(next, struct btrfs_root, dirty_list); update_cowonly_root(trans, root); free_extent_buffer(root->commit_root); root->commit_root = NULL; } return 0; } static int __commit_transaction(struct btrfs_trans_handle *trans, struct btrfs_root *root) { u64 start; u64 end; struct extent_buffer *eb; struct extent_io_tree *tree = &root->fs_info->extent_cache; int ret; while(1) { ret = find_first_extent_bit(tree, 0, &start, &end, EXTENT_DIRTY); if (ret) break; while(start <= end) { eb = find_first_extent_buffer(tree, start); BUG_ON(!eb || eb->start != start); ret = write_tree_block(trans, root, eb); BUG_ON(ret); start += eb->len; clear_extent_buffer_dirty(eb); free_extent_buffer(eb); } } return 0; } int btrfs_commit_transaction(struct btrfs_trans_handle *trans, struct btrfs_root *root) { u64 transid = trans->transid; int ret = 0; struct btrfs_fs_info *fs_info = root->fs_info; if (root->commit_root == root->node) goto commit_tree; if (root == root->fs_info->tree_root) goto commit_tree; free_extent_buffer(root->commit_root); root->commit_root = NULL; btrfs_set_root_bytenr(&root->root_item, root->node->start); btrfs_set_root_generation(&root->root_item, trans->transid); root->root_item.level = btrfs_header_level(root->node); ret = btrfs_update_root(trans, root->fs_info->tree_root, &root->root_key, &root->root_item); BUG_ON(ret); commit_tree: ret = commit_tree_roots(trans, fs_info); BUG_ON(ret); ret = __commit_transaction(trans, root); BUG_ON(ret); write_ctree_super(trans, root); btrfs_finish_extent_commit(trans, fs_info->extent_root, &fs_info->pinned_extents); btrfs_free_transaction(root, trans); free_extent_buffer(root->commit_root); root->commit_root = NULL; fs_info->running_transaction = NULL; fs_info->last_trans_committed = transid; return 0; } static int find_and_setup_root(struct btrfs_root *tree_root, struct btrfs_fs_info *fs_info, u64 objectid, struct btrfs_root *root) { int ret; u32 blocksize; u64 generation; __setup_root(tree_root->nodesize, tree_root->leafsize, tree_root->sectorsize, tree_root->stripesize, root, fs_info, objectid); ret = btrfs_find_last_root(tree_root, objectid, &root->root_item, &root->root_key); if (ret) return ret; blocksize = btrfs_level_size(root, btrfs_root_level(&root->root_item)); generation = btrfs_root_generation(&root->root_item); root->node = read_tree_block(root, btrfs_root_bytenr(&root->root_item), blocksize, generation); if (!extent_buffer_uptodate(root->node)) return -EIO; return 0; } static int find_and_setup_log_root(struct btrfs_root *tree_root, struct btrfs_fs_info *fs_info, struct btrfs_super_block *disk_super) { u32 blocksize; u64 blocknr = btrfs_super_log_root(disk_super); struct btrfs_root *log_root = malloc(sizeof(struct btrfs_root)); if (!log_root) return -ENOMEM; if (blocknr == 0) { free(log_root); return 0; } blocksize = btrfs_level_size(tree_root, btrfs_super_log_root_level(disk_super)); __setup_root(tree_root->nodesize, tree_root->leafsize, tree_root->sectorsize, tree_root->stripesize, log_root, fs_info, BTRFS_TREE_LOG_OBJECTID); log_root->node = read_tree_block(tree_root, blocknr, blocksize, btrfs_super_generation(disk_super) + 1); fs_info->log_root_tree = log_root; if (!extent_buffer_uptodate(log_root->node)) { free_extent_buffer(log_root->node); free(log_root); fs_info->log_root_tree = NULL; return -EIO; } return 0; } int btrfs_free_fs_root(struct btrfs_root *root) { if (root->node) free_extent_buffer(root->node); if (root->commit_root) free_extent_buffer(root->commit_root); kfree(root); return 0; } static void __free_fs_root(struct rb_node *node) { struct btrfs_root *root; root = container_of(node, struct btrfs_root, rb_node); btrfs_free_fs_root(root); } FREE_RB_BASED_TREE(fs_roots, __free_fs_root); struct btrfs_root *btrfs_read_fs_root_no_cache(struct btrfs_fs_info *fs_info, struct btrfs_key *location) { struct btrfs_root *root; struct btrfs_root *tree_root = fs_info->tree_root; struct btrfs_path *path; struct extent_buffer *l; u64 generation; u32 blocksize; int ret = 0; root = malloc(sizeof(*root)); if (!root) return ERR_PTR(-ENOMEM); memset(root, 0, sizeof(*root)); if (location->offset == (u64)-1) { ret = find_and_setup_root(tree_root, fs_info, location->objectid, root); if (ret) { free(root); return ERR_PTR(ret); } goto insert; } __setup_root(tree_root->nodesize, tree_root->leafsize, tree_root->sectorsize, tree_root->stripesize, root, fs_info, location->objectid); path = btrfs_alloc_path(); BUG_ON(!path); ret = btrfs_search_slot(NULL, tree_root, location, path, 0, 0); if (ret != 0) { if (ret > 0) ret = -ENOENT; goto out; } l = path->nodes[0]; read_extent_buffer(l, &root->root_item, btrfs_item_ptr_offset(l, path->slots[0]), sizeof(root->root_item)); memcpy(&root->root_key, location, sizeof(*location)); ret = 0; out: btrfs_free_path(path); if (ret) { free(root); return ERR_PTR(ret); } generation = btrfs_root_generation(&root->root_item); blocksize = btrfs_level_size(root, btrfs_root_level(&root->root_item)); root->node = read_tree_block(root, btrfs_root_bytenr(&root->root_item), blocksize, generation); if (!root->node) { free(root); return ERR_PTR(-EIO); } insert: root->ref_cows = 1; return root; } static int btrfs_fs_roots_compare_objectids(struct rb_node *node, void *data) { u64 objectid = *((u64 *)data); struct btrfs_root *root; root = rb_entry(node, struct btrfs_root, rb_node); if (objectid > root->objectid) return 1; else if (objectid < root->objectid) return -1; else return 0; } static int btrfs_fs_roots_compare_roots(struct rb_node *node1, struct rb_node *node2) { struct btrfs_root *root; root = rb_entry(node2, struct btrfs_root, rb_node); return btrfs_fs_roots_compare_objectids(node1, (void *)&root->objectid); } struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_key *location) { struct btrfs_root *root; struct rb_node *node; int ret; u64 objectid = location->objectid; if (location->objectid == BTRFS_ROOT_TREE_OBJECTID) return fs_info->tree_root; if (location->objectid == BTRFS_EXTENT_TREE_OBJECTID) return fs_info->extent_root; if (location->objectid == BTRFS_CHUNK_TREE_OBJECTID) return fs_info->chunk_root; if (location->objectid == BTRFS_DEV_TREE_OBJECTID) return fs_info->dev_root; if (location->objectid == BTRFS_CSUM_TREE_OBJECTID) return fs_info->csum_root; if (location->objectid == BTRFS_QUOTA_TREE_OBJECTID) return fs_info->csum_root; BUG_ON(location->objectid == BTRFS_TREE_RELOC_OBJECTID || location->offset != (u64)-1); node = rb_search(&fs_info->fs_root_tree, (void *)&objectid, btrfs_fs_roots_compare_objectids, NULL); if (node) return container_of(node, struct btrfs_root, rb_node); root = btrfs_read_fs_root_no_cache(fs_info, location); if (IS_ERR(root)) return root; ret = rb_insert(&fs_info->fs_root_tree, &root->rb_node, btrfs_fs_roots_compare_roots); BUG_ON(ret); return root; } void btrfs_free_fs_info(struct btrfs_fs_info *fs_info) { free(fs_info->tree_root); free(fs_info->extent_root); free(fs_info->chunk_root); free(fs_info->dev_root); free(fs_info->csum_root); free(fs_info->quota_root); free(fs_info->super_copy); free(fs_info->log_root_tree); free(fs_info); } struct btrfs_fs_info *btrfs_new_fs_info(int writable, u64 sb_bytenr) { struct btrfs_fs_info *fs_info; fs_info = malloc(sizeof(struct btrfs_fs_info)); if (!fs_info) return NULL; memset(fs_info, 0, sizeof(struct btrfs_fs_info)); fs_info->tree_root = malloc(sizeof(struct btrfs_root)); fs_info->extent_root = malloc(sizeof(struct btrfs_root)); fs_info->chunk_root = malloc(sizeof(struct btrfs_root)); fs_info->dev_root = malloc(sizeof(struct btrfs_root)); fs_info->csum_root = malloc(sizeof(struct btrfs_root)); fs_info->quota_root = malloc(sizeof(struct btrfs_root)); fs_info->super_copy = malloc(BTRFS_SUPER_INFO_SIZE); if (!fs_info->tree_root || !fs_info->extent_root || !fs_info->chunk_root || !fs_info->dev_root || !fs_info->csum_root || !fs_info->quota_root || !fs_info->super_copy) goto free_all; memset(fs_info->super_copy, 0, BTRFS_SUPER_INFO_SIZE); memset(fs_info->tree_root, 0, sizeof(struct btrfs_root)); memset(fs_info->extent_root, 0, sizeof(struct btrfs_root)); memset(fs_info->chunk_root, 0, sizeof(struct btrfs_root)); memset(fs_info->dev_root, 0, sizeof(struct btrfs_root)); memset(fs_info->csum_root, 0, sizeof(struct btrfs_root)); memset(fs_info->quota_root, 0, sizeof(struct btrfs_root)); extent_io_tree_init(&fs_info->extent_cache); extent_io_tree_init(&fs_info->free_space_cache); extent_io_tree_init(&fs_info->block_group_cache); extent_io_tree_init(&fs_info->pinned_extents); extent_io_tree_init(&fs_info->pending_del); extent_io_tree_init(&fs_info->extent_ins); fs_info->fs_root_tree = RB_ROOT; cache_tree_init(&fs_info->mapping_tree.cache_tree); mutex_init(&fs_info->fs_mutex); INIT_LIST_HEAD(&fs_info->dirty_cowonly_roots); INIT_LIST_HEAD(&fs_info->space_info); INIT_LIST_HEAD(&fs_info->recow_ebs); if (!writable) fs_info->readonly = 1; fs_info->super_bytenr = sb_bytenr; fs_info->data_alloc_profile = (u64)-1; fs_info->metadata_alloc_profile = (u64)-1; fs_info->system_alloc_profile = fs_info->metadata_alloc_profile; return fs_info; free_all: btrfs_free_fs_info(fs_info); return NULL; } int btrfs_check_fs_compatibility(struct btrfs_super_block *sb, int writable) { u64 features; features = btrfs_super_incompat_flags(sb) & ~BTRFS_FEATURE_INCOMPAT_SUPP; if (features) { printk("couldn't open because of unsupported " "option features (%Lx).\n", (unsigned long long)features); return -ENOTSUP; } features = btrfs_super_incompat_flags(sb); if (!(features & BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF)) { features |= BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF; btrfs_set_super_incompat_flags(sb, features); } features = btrfs_super_compat_ro_flags(sb) & ~BTRFS_FEATURE_COMPAT_RO_SUPP; if (writable && features) { printk("couldn't open RDWR because of unsupported " "option features (%Lx).\n", (unsigned long long)features); return -ENOTSUP; } return 0; } static int find_best_backup_root(struct btrfs_super_block *super) { struct btrfs_root_backup *backup; u64 orig_gen = btrfs_super_generation(super); u64 gen = 0; int best_index = 0; int i; for (i = 0; i < BTRFS_NUM_BACKUP_ROOTS; i++) { backup = super->super_roots + i; if (btrfs_backup_tree_root_gen(backup) != orig_gen && btrfs_backup_tree_root_gen(backup) > gen) { best_index = i; gen = btrfs_backup_tree_root_gen(backup); } } return best_index; } static int setup_root_or_create_block(struct btrfs_fs_info *fs_info, enum btrfs_open_ctree_flags flags, struct btrfs_root *info_root, u64 objectid, char *str) { struct btrfs_super_block *sb = fs_info->super_copy; struct btrfs_root *root = fs_info->tree_root; u32 leafsize = btrfs_super_leafsize(sb); int ret; ret = find_and_setup_root(root, fs_info, objectid, info_root); if (ret) { printk("Couldn't setup %s tree\n", str); if (!(flags & OPEN_CTREE_PARTIAL)) return -EIO; /* * Need a blank node here just so we don't screw up in the * million of places that assume a root has a valid ->node */ info_root->node = btrfs_find_create_tree_block(info_root, 0, leafsize); if (!info_root->node) return -ENOMEM; clear_extent_buffer_uptodate(NULL, info_root->node); } return 0; } int btrfs_setup_all_roots(struct btrfs_fs_info *fs_info, u64 root_tree_bytenr, enum btrfs_open_ctree_flags flags) { struct btrfs_super_block *sb = fs_info->super_copy; struct btrfs_root *root; struct btrfs_key key; u32 sectorsize; u32 nodesize; u32 leafsize; u32 stripesize; u64 generation; u32 blocksize; int ret; nodesize = btrfs_super_nodesize(sb); leafsize = btrfs_super_leafsize(sb); sectorsize = btrfs_super_sectorsize(sb); stripesize = btrfs_super_stripesize(sb); root = fs_info->tree_root; __setup_root(nodesize, leafsize, sectorsize, stripesize, root, fs_info, BTRFS_ROOT_TREE_OBJECTID); blocksize = btrfs_level_size(root, btrfs_super_root_level(sb)); generation = btrfs_super_generation(sb); if (!root_tree_bytenr && !(flags & OPEN_CTREE_BACKUP_ROOT)) { root_tree_bytenr = btrfs_super_root(sb); } else if (flags & OPEN_CTREE_BACKUP_ROOT) { struct btrfs_root_backup *backup; int index = find_best_backup_root(sb); if (index >= BTRFS_NUM_BACKUP_ROOTS) { fprintf(stderr, "Invalid backup root number\n"); return -EIO; } backup = fs_info->super_copy->super_roots + index; root_tree_bytenr = btrfs_backup_tree_root(backup); generation = btrfs_backup_tree_root_gen(backup); } root->node = read_tree_block(root, root_tree_bytenr, blocksize, generation); if (!extent_buffer_uptodate(root->node)) { fprintf(stderr, "Couldn't read tree root\n"); return -EIO; } ret = setup_root_or_create_block(fs_info, flags, fs_info->extent_root, BTRFS_EXTENT_TREE_OBJECTID, "extent"); if (ret) return ret; fs_info->extent_root->track_dirty = 1; ret = find_and_setup_root(root, fs_info, BTRFS_DEV_TREE_OBJECTID, fs_info->dev_root); if (ret) { printk("Couldn't setup device tree\n"); return -EIO; } fs_info->dev_root->track_dirty = 1; ret = setup_root_or_create_block(fs_info, flags, fs_info->csum_root, BTRFS_CSUM_TREE_OBJECTID, "csum"); if (ret) return ret; fs_info->csum_root->track_dirty = 1; ret = find_and_setup_root(root, fs_info, BTRFS_QUOTA_TREE_OBJECTID, fs_info->quota_root); if (ret == 0) fs_info->quota_enabled = 1; ret = find_and_setup_log_root(root, fs_info, sb); if (ret) { printk("Couldn't setup log root tree\n"); if (!(flags & OPEN_CTREE_PARTIAL)) return -EIO; } fs_info->generation = generation; fs_info->last_trans_committed = generation; if (extent_buffer_uptodate(fs_info->extent_root->node) && !(flags & OPEN_CTREE_NO_BLOCK_GROUPS)) btrfs_read_block_groups(fs_info->tree_root); key.objectid = BTRFS_FS_TREE_OBJECTID; key.type = BTRFS_ROOT_ITEM_KEY; key.offset = (u64)-1; fs_info->fs_root = btrfs_read_fs_root(fs_info, &key); if (IS_ERR(fs_info->fs_root)) return -EIO; return 0; } void btrfs_release_all_roots(struct btrfs_fs_info *fs_info) { if (fs_info->quota_root) free_extent_buffer(fs_info->quota_root->node); if (fs_info->csum_root) free_extent_buffer(fs_info->csum_root->node); if (fs_info->dev_root) free_extent_buffer(fs_info->dev_root->node); if (fs_info->extent_root) free_extent_buffer(fs_info->extent_root->node); if (fs_info->tree_root) free_extent_buffer(fs_info->tree_root->node); if (fs_info->log_root_tree) free_extent_buffer(fs_info->log_root_tree->node); if (fs_info->chunk_root) free_extent_buffer(fs_info->chunk_root->node); } static void free_map_lookup(struct cache_extent *ce) { struct map_lookup *map; map = container_of(ce, struct map_lookup, ce); kfree(map); } FREE_EXTENT_CACHE_BASED_TREE(mapping_cache, free_map_lookup); void btrfs_cleanup_all_caches(struct btrfs_fs_info *fs_info) { while (!list_empty(&fs_info->recow_ebs)) { struct extent_buffer *eb; eb = list_first_entry(&fs_info->recow_ebs, struct extent_buffer, recow); list_del_init(&eb->recow); free_extent_buffer(eb); } free_mapping_cache_tree(&fs_info->mapping_tree.cache_tree); extent_io_tree_cleanup(&fs_info->extent_cache); extent_io_tree_cleanup(&fs_info->free_space_cache); extent_io_tree_cleanup(&fs_info->block_group_cache); extent_io_tree_cleanup(&fs_info->pinned_extents); extent_io_tree_cleanup(&fs_info->pending_del); extent_io_tree_cleanup(&fs_info->extent_ins); } int btrfs_scan_fs_devices(int fd, const char *path, struct btrfs_fs_devices **fs_devices, u64 sb_bytenr, int super_recover) { u64 total_devs; u64 dev_size; int ret; if (!sb_bytenr) sb_bytenr = BTRFS_SUPER_INFO_OFFSET; dev_size = lseek(fd, 0, SEEK_END); if (dev_size < 0) return (int)(dev_size); lseek(fd, 0, SEEK_SET); if (sb_bytenr > dev_size) { fprintf(stderr, "Superblock bytenr is larger than device size\n"); return -EINVAL; } ret = btrfs_scan_one_device(fd, path, fs_devices, &total_devs, sb_bytenr, super_recover); if (ret) { fprintf(stderr, "No valid Btrfs found on %s\n", path); return ret; } if (total_devs != 1) { ret = btrfs_scan_lblkid(); if (ret) return ret; } return 0; } int btrfs_setup_chunk_tree_and_device_map(struct btrfs_fs_info *fs_info) { struct btrfs_super_block *sb = fs_info->super_copy; u32 sectorsize; u32 nodesize; u32 leafsize; u32 blocksize; u32 stripesize; u64 generation; int ret; nodesize = btrfs_super_nodesize(sb); leafsize = btrfs_super_leafsize(sb); sectorsize = btrfs_super_sectorsize(sb); stripesize = btrfs_super_stripesize(sb); __setup_root(nodesize, leafsize, sectorsize, stripesize, fs_info->chunk_root, fs_info, BTRFS_CHUNK_TREE_OBJECTID); ret = btrfs_read_sys_array(fs_info->chunk_root); if (ret) return ret; blocksize = btrfs_level_size(fs_info->chunk_root, btrfs_super_chunk_root_level(sb)); generation = btrfs_super_chunk_root_generation(sb); fs_info->chunk_root->node = read_tree_block(fs_info->chunk_root, btrfs_super_chunk_root(sb), blocksize, generation); if (!fs_info->chunk_root->node || !extent_buffer_uptodate(fs_info->chunk_root->node)) { fprintf(stderr, "Couldn't read chunk root\n"); return -EIO; } if (!(btrfs_super_flags(sb) & BTRFS_SUPER_FLAG_METADUMP)) { ret = btrfs_read_chunk_tree(fs_info->chunk_root); if (ret) { fprintf(stderr, "Couldn't read chunk tree\n"); return ret; } } return 0; } static struct btrfs_fs_info *__open_ctree_fd(int fp, const char *path, u64 sb_bytenr, u64 root_tree_bytenr, enum btrfs_open_ctree_flags flags) { struct btrfs_fs_info *fs_info; struct btrfs_super_block *disk_super; struct btrfs_fs_devices *fs_devices = NULL; struct extent_buffer *eb; int ret; int oflags; if (sb_bytenr == 0) sb_bytenr = BTRFS_SUPER_INFO_OFFSET; /* try to drop all the caches */ if (posix_fadvise(fp, 0, 0, POSIX_FADV_DONTNEED)) fprintf(stderr, "Warning, could not drop caches\n"); fs_info = btrfs_new_fs_info(flags & OPEN_CTREE_WRITES, sb_bytenr); if (!fs_info) { fprintf(stderr, "Failed to allocate memory for fs_info\n"); return NULL; } if (flags & OPEN_CTREE_RESTORE) fs_info->on_restoring = 1; ret = btrfs_scan_fs_devices(fp, path, &fs_devices, sb_bytenr, (flags & OPEN_CTREE_RECOVER_SUPER)); if (ret) goto out; fs_info->fs_devices = fs_devices; if (flags & OPEN_CTREE_WRITES) oflags = O_RDWR; else oflags = O_RDONLY; if (flags & OPEN_CTREE_EXCLUSIVE) oflags |= O_EXCL; ret = btrfs_open_devices(fs_devices, oflags); if (ret) goto out; disk_super = fs_info->super_copy; if (!(flags & OPEN_CTREE_RECOVER_SUPER)) ret = btrfs_read_dev_super(fs_devices->latest_bdev, disk_super, sb_bytenr, 1); else ret = btrfs_read_dev_super(fp, disk_super, sb_bytenr, 0); if (ret) { printk("No valid btrfs found\n"); goto out_devices; } memcpy(fs_info->fsid, &disk_super->fsid, BTRFS_FSID_SIZE); ret = btrfs_check_fs_compatibility(fs_info->super_copy, flags & OPEN_CTREE_WRITES); if (ret) goto out_devices; ret = btrfs_setup_chunk_tree_and_device_map(fs_info); if (ret) goto out_chunk; eb = fs_info->chunk_root->node; read_extent_buffer(eb, fs_info->chunk_tree_uuid, btrfs_header_chunk_tree_uuid(eb), BTRFS_UUID_SIZE); ret = btrfs_setup_all_roots(fs_info, root_tree_bytenr, flags); if (ret) goto out_chunk; return fs_info; out_chunk: btrfs_release_all_roots(fs_info); btrfs_cleanup_all_caches(fs_info); out_devices: btrfs_close_devices(fs_devices); out: btrfs_free_fs_info(fs_info); return NULL; } struct btrfs_fs_info *open_ctree_fs_info(const char *filename, u64 sb_bytenr, u64 root_tree_bytenr, enum btrfs_open_ctree_flags flags) { int fp; struct btrfs_fs_info *info; int oflags = O_CREAT | O_RDWR; if (!(flags & OPEN_CTREE_WRITES)) oflags = O_RDONLY; fp = open(filename, oflags, 0600); if (fp < 0) { fprintf (stderr, "Could not open %s\n", filename); return NULL; } info = __open_ctree_fd(fp, filename, sb_bytenr, root_tree_bytenr, flags); close(fp); return info; } struct btrfs_root *open_ctree(const char *filename, u64 sb_bytenr, enum btrfs_open_ctree_flags flags) { struct btrfs_fs_info *info; info = open_ctree_fs_info(filename, sb_bytenr, 0, flags); if (!info) return NULL; return info->fs_root; } struct btrfs_root *open_ctree_fd(int fp, const char *path, u64 sb_bytenr, enum btrfs_open_ctree_flags flags) { struct btrfs_fs_info *info; info = __open_ctree_fd(fp, path, sb_bytenr, 0, flags); if (!info) return NULL; return info->fs_root; } int btrfs_read_dev_super(int fd, struct btrfs_super_block *sb, u64 sb_bytenr, int super_recover) { u8 fsid[BTRFS_FSID_SIZE]; int fsid_is_initialized = 0; struct btrfs_super_block buf; int i; int ret; int max_super = super_recover ? BTRFS_SUPER_MIRROR_MAX : 1; u64 transid = 0; u64 bytenr; if (sb_bytenr != BTRFS_SUPER_INFO_OFFSET) { ret = pread64(fd, &buf, sizeof(buf), sb_bytenr); if (ret < sizeof(buf)) return -1; if (btrfs_super_bytenr(&buf) != sb_bytenr || btrfs_super_magic(&buf) != BTRFS_MAGIC) return -1; memcpy(sb, &buf, sizeof(*sb)); return 0; } /* * we would like to check all the supers, but that would make * a btrfs mount succeed after a mkfs from a different FS. * So, we need to add a special mount option to scan for * later supers, using BTRFS_SUPER_MIRROR_MAX instead */ for (i = 0; i < max_super; i++) { bytenr = btrfs_sb_offset(i); ret = pread64(fd, &buf, sizeof(buf), bytenr); if (ret < sizeof(buf)) break; if (btrfs_super_bytenr(&buf) != bytenr ) continue; /* if magic is NULL, the device was removed */ if (btrfs_super_magic(&buf) == 0 && i == 0) return -1; if (btrfs_super_magic(&buf) != BTRFS_MAGIC) continue; if (!fsid_is_initialized) { memcpy(fsid, buf.fsid, sizeof(fsid)); fsid_is_initialized = 1; } else if (memcmp(fsid, buf.fsid, sizeof(fsid))) { /* * the superblocks (the original one and * its backups) contain data of different * filesystems -> the super cannot be trusted */ continue; } if (btrfs_super_generation(&buf) > transid) { memcpy(sb, &buf, sizeof(*sb)); transid = btrfs_super_generation(&buf); } } return transid > 0 ? 0 : -1; } static int write_dev_supers(struct btrfs_root *root, struct btrfs_super_block *sb, struct btrfs_device *device) { u64 bytenr; u32 crc; int i, ret; if (root->fs_info->super_bytenr != BTRFS_SUPER_INFO_OFFSET) { btrfs_set_super_bytenr(sb, root->fs_info->super_bytenr); crc = ~(u32)0; crc = btrfs_csum_data(NULL, (char *)sb + BTRFS_CSUM_SIZE, crc, BTRFS_SUPER_INFO_SIZE - BTRFS_CSUM_SIZE); btrfs_csum_final(crc, (char *)&sb->csum[0]); /* * super_copy is BTRFS_SUPER_INFO_SIZE bytes and is * zero filled, we can use it directly */ ret = pwrite64(device->fd, root->fs_info->super_copy, BTRFS_SUPER_INFO_SIZE, root->fs_info->super_bytenr); BUG_ON(ret != BTRFS_SUPER_INFO_SIZE); return 0; } for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) { bytenr = btrfs_sb_offset(i); if (bytenr + BTRFS_SUPER_INFO_SIZE > device->total_bytes) break; btrfs_set_super_bytenr(sb, bytenr); crc = ~(u32)0; crc = btrfs_csum_data(NULL, (char *)sb + BTRFS_CSUM_SIZE, crc, BTRFS_SUPER_INFO_SIZE - BTRFS_CSUM_SIZE); btrfs_csum_final(crc, (char *)&sb->csum[0]); /* * super_copy is BTRFS_SUPER_INFO_SIZE bytes and is * zero filled, we can use it directly */ ret = pwrite64(device->fd, root->fs_info->super_copy, BTRFS_SUPER_INFO_SIZE, bytenr); BUG_ON(ret != BTRFS_SUPER_INFO_SIZE); } return 0; } int write_all_supers(struct btrfs_root *root) { struct list_head *cur; struct list_head *head = &root->fs_info->fs_devices->devices; struct btrfs_device *dev; struct btrfs_super_block *sb; struct btrfs_dev_item *dev_item; int ret; u64 flags; sb = root->fs_info->super_copy; dev_item = &sb->dev_item; list_for_each(cur, head) { dev = list_entry(cur, struct btrfs_device, dev_list); if (!dev->writeable) continue; btrfs_set_stack_device_generation(dev_item, 0); btrfs_set_stack_device_type(dev_item, dev->type); btrfs_set_stack_device_id(dev_item, dev->devid); btrfs_set_stack_device_total_bytes(dev_item, dev->total_bytes); btrfs_set_stack_device_bytes_used(dev_item, dev->bytes_used); btrfs_set_stack_device_io_align(dev_item, dev->io_align); btrfs_set_stack_device_io_width(dev_item, dev->io_width); btrfs_set_stack_device_sector_size(dev_item, dev->sector_size); memcpy(dev_item->uuid, dev->uuid, BTRFS_UUID_SIZE); memcpy(dev_item->fsid, dev->fs_devices->fsid, BTRFS_UUID_SIZE); flags = btrfs_super_flags(sb); btrfs_set_super_flags(sb, flags | BTRFS_HEADER_FLAG_WRITTEN); ret = write_dev_supers(root, sb, dev); BUG_ON(ret); } return 0; } int write_ctree_super(struct btrfs_trans_handle *trans, struct btrfs_root *root) { int ret; struct btrfs_root *tree_root = root->fs_info->tree_root; struct btrfs_root *chunk_root = root->fs_info->chunk_root; if (root->fs_info->readonly) return 0; btrfs_set_super_generation(root->fs_info->super_copy, trans->transid); btrfs_set_super_root(root->fs_info->super_copy, tree_root->node->start); btrfs_set_super_root_level(root->fs_info->super_copy, btrfs_header_level(tree_root->node)); btrfs_set_super_chunk_root(root->fs_info->super_copy, chunk_root->node->start); btrfs_set_super_chunk_root_level(root->fs_info->super_copy, btrfs_header_level(chunk_root->node)); btrfs_set_super_chunk_root_generation(root->fs_info->super_copy, btrfs_header_generation(chunk_root->node)); ret = write_all_supers(root); if (ret) fprintf(stderr, "failed to write new super block err %d\n", ret); return ret; } int close_ctree(struct btrfs_root *root) { int ret; struct btrfs_trans_handle *trans; struct btrfs_fs_info *fs_info = root->fs_info; if (fs_info->last_trans_committed != fs_info->generation) { trans = btrfs_start_transaction(root, 1); btrfs_commit_transaction(trans, root); trans = btrfs_start_transaction(root, 1); ret = commit_tree_roots(trans, fs_info); BUG_ON(ret); ret = __commit_transaction(trans, root); BUG_ON(ret); write_ctree_super(trans, root); btrfs_free_transaction(root, trans); } btrfs_free_block_groups(fs_info); free_fs_roots_tree(&fs_info->fs_root_tree); btrfs_release_all_roots(fs_info); btrfs_close_devices(fs_info->fs_devices); btrfs_cleanup_all_caches(fs_info); btrfs_free_fs_info(fs_info); return 0; } int clean_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct extent_buffer *eb) { return clear_extent_buffer_dirty(eb); } int wait_on_tree_block_writeback(struct btrfs_root *root, struct extent_buffer *eb) { return 0; } void btrfs_mark_buffer_dirty(struct extent_buffer *eb) { set_extent_buffer_dirty(eb); } int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid) { int ret; ret = extent_buffer_uptodate(buf); if (!ret) return ret; ret = verify_parent_transid(buf->tree, buf, parent_transid, 1); return !ret; } int btrfs_set_buffer_uptodate(struct extent_buffer *eb) { return set_extent_buffer_uptodate(eb); } partclone-0.2.86/src/btrfs/disk-io.h000066400000000000000000000113651262102574200172240ustar00rootroot00000000000000/* * Copyright (C) 2007 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. */ #ifndef __DISKIO__ #define __DISKIO__ #define BTRFS_SUPER_INFO_OFFSET (64 * 1024) #define BTRFS_SUPER_INFO_SIZE 4096 #define BTRFS_SUPER_MIRROR_MAX 3 #define BTRFS_SUPER_MIRROR_SHIFT 12 enum btrfs_open_ctree_flags { OPEN_CTREE_WRITES = 1, OPEN_CTREE_PARTIAL = 2, OPEN_CTREE_BACKUP_ROOT = 4, OPEN_CTREE_RECOVER_SUPER = 8, OPEN_CTREE_RESTORE = 16, OPEN_CTREE_NO_BLOCK_GROUPS = 32, OPEN_CTREE_EXCLUSIVE = 64, }; static inline u64 btrfs_sb_offset(int mirror) { u64 start = 16 * 1024; if (mirror) return start << (BTRFS_SUPER_MIRROR_SHIFT * mirror); return BTRFS_SUPER_INFO_OFFSET; } struct btrfs_device; int read_whole_eb(struct btrfs_fs_info *info, struct extent_buffer *eb, int mirror); struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr, u32 blocksize, u64 parent_transid); void readahead_tree_block(struct btrfs_root *root, u64 bytenr, u32 blocksize, u64 parent_transid); struct extent_buffer *btrfs_find_create_tree_block(struct btrfs_root *root, u64 bytenr, u32 blocksize); int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize, u32 stripesize, struct btrfs_root *root, struct btrfs_fs_info *fs_info, u64 objectid); int clean_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct extent_buffer *buf); void btrfs_free_fs_info(struct btrfs_fs_info *fs_info); struct btrfs_fs_info *btrfs_new_fs_info(int writable, u64 sb_bytenr); int btrfs_check_fs_compatibility(struct btrfs_super_block *sb, int writable); int btrfs_setup_all_roots(struct btrfs_fs_info *fs_info, u64 root_tree_bytenr, enum btrfs_open_ctree_flags flags); void btrfs_release_all_roots(struct btrfs_fs_info *fs_info); void btrfs_cleanup_all_caches(struct btrfs_fs_info *fs_info); int btrfs_scan_fs_devices(int fd, const char *path, struct btrfs_fs_devices **fs_devices, u64 sb_bytenr, int super_recover); int btrfs_setup_chunk_tree_and_device_map(struct btrfs_fs_info *fs_info); struct btrfs_root *open_ctree(const char *filename, u64 sb_bytenr, enum btrfs_open_ctree_flags flags); struct btrfs_root *open_ctree_fd(int fp, const char *path, u64 sb_bytenr, enum btrfs_open_ctree_flags flags); struct btrfs_fs_info *open_ctree_fs_info(const char *filename, u64 sb_bytenr, u64 root_tree_bytenr, enum btrfs_open_ctree_flags flags); int close_ctree(struct btrfs_root *root); int write_all_supers(struct btrfs_root *root); int write_ctree_super(struct btrfs_trans_handle *trans, struct btrfs_root *root); int btrfs_read_dev_super(int fd, struct btrfs_super_block *sb, u64 sb_bytenr, int super_recover); int btrfs_map_bh_to_logical(struct btrfs_root *root, struct extent_buffer *bh, u64 logical); struct extent_buffer *btrfs_find_tree_block(struct btrfs_root *root, u64 bytenr, u32 blocksize); struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_key *location); struct btrfs_root *btrfs_read_fs_root_no_cache(struct btrfs_fs_info *fs_info, struct btrfs_key *location); int btrfs_free_fs_root(struct btrfs_root *root); void btrfs_mark_buffer_dirty(struct extent_buffer *buf); int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid); int btrfs_set_buffer_uptodate(struct extent_buffer *buf); int wait_on_tree_block_writeback(struct btrfs_root *root, struct extent_buffer *buf); u32 btrfs_csum_data(struct btrfs_root *root, char *data, u32 seed, size_t len); void btrfs_csum_final(u32 crc, char *result); int btrfs_commit_transaction(struct btrfs_trans_handle *trans, struct btrfs_root *root); int btrfs_open_device(struct btrfs_device *dev); int csum_tree_block_size(struct extent_buffer *buf, u16 csum_sectorsize, int verify); int verify_tree_block_csum_silent(struct extent_buffer *buf, u16 csum_size); int btrfs_read_buffer(struct extent_buffer *buf, u64 parent_transid); int write_and_map_eb(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct extent_buffer *eb); #endif /* raid6.c */ void raid6_gen_syndrome(int disks, size_t bytes, void **ptrs); partclone-0.2.86/src/btrfs/extent-cache.c000066400000000000000000000146671262102574200202400ustar00rootroot00000000000000/* * Copyright (C) 2007 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. */ #include #include #include "kerncompat.h" #include "extent-cache.h" #include "rbtree-utils.h" struct cache_extent_search_range { u64 objectid; u64 start; u64 size; }; static int cache_tree_comp_range(struct rb_node *node, void *data) { struct cache_extent *entry; struct cache_extent_search_range *range; range = (struct cache_extent_search_range *)data; entry = rb_entry(node, struct cache_extent, rb_node); if (entry->start + entry->size <= range->start) return 1; else if (range->start + range->size <= entry->start) return -1; else return 0; } static int cache_tree_comp_nodes(struct rb_node *node1, struct rb_node *node2) { struct cache_extent *entry; struct cache_extent_search_range range; entry = rb_entry(node2, struct cache_extent, rb_node); range.start = entry->start; range.size = entry->size; return cache_tree_comp_range(node1, (void *)&range); } static int cache_tree_comp_range2(struct rb_node *node, void *data) { struct cache_extent *entry; struct cache_extent_search_range *range; range = (struct cache_extent_search_range *)data; entry = rb_entry(node, struct cache_extent, rb_node); if (entry->objectid < range->objectid) return 1; else if (entry->objectid > range->objectid) return -1; else if (entry->start + entry->size <= range->start) return 1; else if (range->start + range->size <= entry->start) return -1; else return 0; } static int cache_tree_comp_nodes2(struct rb_node *node1, struct rb_node *node2) { struct cache_extent *entry; struct cache_extent_search_range range; entry = rb_entry(node2, struct cache_extent, rb_node); range.objectid = entry->objectid; range.start = entry->start; range.size = entry->size; return cache_tree_comp_range2(node1, (void *)&range); } void cache_tree_init(struct cache_tree *tree) { tree->root = RB_ROOT; } static struct cache_extent * alloc_cache_extent(u64 objectid, u64 start, u64 size) { struct cache_extent *pe = malloc(sizeof(*pe)); if (!pe) return pe; pe->objectid = objectid; pe->start = start; pe->size = size; return pe; } static int __add_cache_extent(struct cache_tree *tree, u64 objectid, u64 start, u64 size) { struct cache_extent *pe = alloc_cache_extent(objectid, start, size); int ret; if (!pe) { fprintf(stderr, "memory allocation failed\n"); exit(1); } ret = insert_cache_extent(tree, pe); if (ret) free(pe); return ret; } int add_cache_extent(struct cache_tree *tree, u64 start, u64 size) { return __add_cache_extent(tree, 0, start, size); } int add_cache_extent2(struct cache_tree *tree, u64 objectid, u64 start, u64 size) { return __add_cache_extent(tree, objectid, start, size); } int insert_cache_extent(struct cache_tree *tree, struct cache_extent *pe) { return rb_insert(&tree->root, &pe->rb_node, cache_tree_comp_nodes); } int insert_cache_extent2(struct cache_tree *tree, struct cache_extent *pe) { return rb_insert(&tree->root, &pe->rb_node, cache_tree_comp_nodes2); } struct cache_extent *lookup_cache_extent(struct cache_tree *tree, u64 start, u64 size) { struct rb_node *node; struct cache_extent *entry; struct cache_extent_search_range range; range.start = start; range.size = size; node = rb_search(&tree->root, &range, cache_tree_comp_range, NULL); if (!node) return NULL; entry = rb_entry(node, struct cache_extent, rb_node); return entry; } struct cache_extent *lookup_cache_extent2(struct cache_tree *tree, u64 objectid, u64 start, u64 size) { struct rb_node *node; struct cache_extent *entry; struct cache_extent_search_range range; range.objectid = objectid; range.start = start; range.size = size; node = rb_search(&tree->root, &range, cache_tree_comp_range2, NULL); if (!node) return NULL; entry = rb_entry(node, struct cache_extent, rb_node); return entry; } struct cache_extent *search_cache_extent(struct cache_tree *tree, u64 start) { struct rb_node *next; struct rb_node *node; struct cache_extent *entry; struct cache_extent_search_range range; range.start = start; range.size = 1; node = rb_search(&tree->root, &range, cache_tree_comp_range, &next); if (!node) node = next; if (!node) return NULL; entry = rb_entry(node, struct cache_extent, rb_node); return entry; } struct cache_extent *search_cache_extent2(struct cache_tree *tree, u64 objectid, u64 start) { struct rb_node *next; struct rb_node *node; struct cache_extent *entry; struct cache_extent_search_range range; range.objectid = objectid; range.start = start; range.size = 1; node = rb_search(&tree->root, &range, cache_tree_comp_range2, &next); if (!node) node = next; if (!node) return NULL; entry = rb_entry(node, struct cache_extent, rb_node); return entry; } struct cache_extent *first_cache_extent(struct cache_tree *tree) { struct rb_node *node = rb_first(&tree->root); if (!node) return NULL; return rb_entry(node, struct cache_extent, rb_node); } struct cache_extent *prev_cache_extent(struct cache_extent *pe) { struct rb_node *node = rb_prev(&pe->rb_node); if (!node) return NULL; return rb_entry(node, struct cache_extent, rb_node); } struct cache_extent *next_cache_extent(struct cache_extent *pe) { struct rb_node *node = rb_next(&pe->rb_node); if (!node) return NULL; return rb_entry(node, struct cache_extent, rb_node); } void remove_cache_extent(struct cache_tree *tree, struct cache_extent *pe) { rb_erase(&pe->rb_node, &tree->root); } void cache_tree_free_extents(struct cache_tree *tree, free_cache_extent free_func) { struct cache_extent *ce; while ((ce = first_cache_extent(tree))) { remove_cache_extent(tree, ce); free_func(ce); } } static void free_extent_cache(struct cache_extent *pe) { free(pe); } void free_extent_cache_tree(struct cache_tree *tree) { cache_tree_free_extents(tree, free_extent_cache); } partclone-0.2.86/src/btrfs/extent-cache.h000066400000000000000000000050141262102574200202270ustar00rootroot00000000000000/* * Copyright (C) 2007 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. */ #ifndef __EXTENT_CACHE_H__ #define __EXTENT_CACHE_H__ #if BTRFS_FLAT_INCLUDES #include "kerncompat.h" #include "rbtree.h" #else #include #include #endif /* BTRFS_FLAT_INCLUDES */ struct cache_tree { struct rb_root root; }; struct cache_extent { struct rb_node rb_node; u64 objectid; u64 start; u64 size; }; void cache_tree_init(struct cache_tree *tree); struct cache_extent *first_cache_extent(struct cache_tree *tree); struct cache_extent *prev_cache_extent(struct cache_extent *pe); struct cache_extent *next_cache_extent(struct cache_extent *pe); struct cache_extent *search_cache_extent(struct cache_tree *tree, u64 start); struct cache_extent *lookup_cache_extent(struct cache_tree *tree, u64 start, u64 size); int add_cache_extent(struct cache_tree *tree, u64 start, u64 size); int insert_cache_extent(struct cache_tree *tree, struct cache_extent *pe); void remove_cache_extent(struct cache_tree *tree, struct cache_extent *pe); static inline int cache_tree_empty(struct cache_tree *tree) { return RB_EMPTY_ROOT(&tree->root); } typedef void (*free_cache_extent)(struct cache_extent *pe); void cache_tree_free_extents(struct cache_tree *tree, free_cache_extent free_func); #define FREE_EXTENT_CACHE_BASED_TREE(name, free_func) \ static void free_##name##_tree(struct cache_tree *tree) \ { \ cache_tree_free_extents(tree, free_func); \ } void free_extent_cache_tree(struct cache_tree *tree); struct cache_extent *search_cache_extent2(struct cache_tree *tree, u64 objectid, u64 start); struct cache_extent *lookup_cache_extent2(struct cache_tree *tree, u64 objectid, u64 start, u64 size); int add_cache_extent2(struct cache_tree *tree, u64 objectid, u64 start, u64 size); int insert_cache_extent2(struct cache_tree *tree, struct cache_extent *pe); #endif partclone-0.2.86/src/btrfs/extent-tree.c000066400000000000000000002715601262102574200201310ustar00rootroot00000000000000/* * Copyright (C) 2007 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. */ #include #include #include #include "kerncompat.h" #include "radix-tree.h" #include "ctree.h" #include "disk-io.h" #include "print-tree.h" #include "transaction.h" #include "crc32c.h" #include "volumes.h" #include "free-space-cache.h" #include "math.h" #include "utils.h" #define PENDING_EXTENT_INSERT 0 #define PENDING_EXTENT_DELETE 1 #define PENDING_BACKREF_UPDATE 2 struct pending_extent_op { int type; u64 bytenr; u64 num_bytes; u64 flags; struct btrfs_disk_key key; int level; }; static int alloc_reserved_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 root_objectid, u64 generation, u64 flags, struct btrfs_disk_key *key, int level, struct btrfs_key *ins); static int __free_extent(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 bytenr, u64 num_bytes, u64 parent, u64 root_objectid, u64 owner_objectid, u64 owner_offset, int refs_to_drop); static int finish_current_insert(struct btrfs_trans_handle *trans, struct btrfs_root *extent_root); static int del_pending_extents(struct btrfs_trans_handle *trans, struct btrfs_root *extent_root); static struct btrfs_block_group_cache * btrfs_find_block_group(struct btrfs_root *root, struct btrfs_block_group_cache *hint, u64 search_start, int data, int owner); static int remove_sb_from_cache(struct btrfs_root *root, struct btrfs_block_group_cache *cache) { u64 bytenr; u64 *logical; int stripe_len; int i, nr, ret; struct extent_io_tree *free_space_cache; free_space_cache = &root->fs_info->free_space_cache; for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) { bytenr = btrfs_sb_offset(i); ret = btrfs_rmap_block(&root->fs_info->mapping_tree, cache->key.objectid, bytenr, 0, &logical, &nr, &stripe_len); BUG_ON(ret); while (nr--) { clear_extent_dirty(free_space_cache, logical[nr], logical[nr] + stripe_len - 1, GFP_NOFS); } kfree(logical); } return 0; } static int cache_block_group(struct btrfs_root *root, struct btrfs_block_group_cache *block_group) { struct btrfs_path *path; int ret; struct btrfs_key key; struct extent_buffer *leaf; struct extent_io_tree *free_space_cache; int slot; u64 last; u64 hole_size; if (!block_group) return 0; root = root->fs_info->extent_root; free_space_cache = &root->fs_info->free_space_cache; if (block_group->cached) return 0; path = btrfs_alloc_path(); if (!path) return -ENOMEM; path->reada = 2; last = max_t(u64, block_group->key.objectid, BTRFS_SUPER_INFO_OFFSET); key.objectid = last; key.offset = 0; key.type = 0; ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); if (ret < 0) goto err; while(1) { leaf = path->nodes[0]; slot = path->slots[0]; if (slot >= btrfs_header_nritems(leaf)) { ret = btrfs_next_leaf(root, path); if (ret < 0) goto err; if (ret == 0) { continue; } else { break; } } btrfs_item_key_to_cpu(leaf, &key, slot); if (key.objectid < block_group->key.objectid) { goto next; } if (key.objectid >= block_group->key.objectid + block_group->key.offset) { break; } if (key.type == BTRFS_EXTENT_ITEM_KEY || key.type == BTRFS_METADATA_ITEM_KEY) { if (key.objectid > last) { hole_size = key.objectid - last; set_extent_dirty(free_space_cache, last, last + hole_size - 1, GFP_NOFS); } if (key.type == BTRFS_METADATA_ITEM_KEY) last = key.objectid + root->leafsize; else last = key.objectid + key.offset; } next: path->slots[0]++; } if (block_group->key.objectid + block_group->key.offset > last) { hole_size = block_group->key.objectid + block_group->key.offset - last; set_extent_dirty(free_space_cache, last, last + hole_size - 1, GFP_NOFS); } remove_sb_from_cache(root, block_group); block_group->cached = 1; err: btrfs_free_path(path); return 0; } struct btrfs_block_group_cache *btrfs_lookup_first_block_group(struct btrfs_fs_info *info, u64 bytenr) { struct extent_io_tree *block_group_cache; struct btrfs_block_group_cache *block_group = NULL; u64 ptr; u64 start; u64 end; int ret; bytenr = max_t(u64, bytenr, BTRFS_SUPER_INFO_OFFSET + BTRFS_SUPER_INFO_SIZE); block_group_cache = &info->block_group_cache; ret = find_first_extent_bit(block_group_cache, bytenr, &start, &end, BLOCK_GROUP_DATA | BLOCK_GROUP_METADATA | BLOCK_GROUP_SYSTEM); if (ret) { return NULL; } ret = get_state_private(block_group_cache, start, &ptr); if (ret) return NULL; block_group = (struct btrfs_block_group_cache *)(unsigned long)ptr; return block_group; } struct btrfs_block_group_cache *btrfs_lookup_block_group(struct btrfs_fs_info *info, u64 bytenr) { struct extent_io_tree *block_group_cache; struct btrfs_block_group_cache *block_group = NULL; u64 ptr; u64 start; u64 end; int ret; block_group_cache = &info->block_group_cache; ret = find_first_extent_bit(block_group_cache, bytenr, &start, &end, BLOCK_GROUP_DATA | BLOCK_GROUP_METADATA | BLOCK_GROUP_SYSTEM); if (ret) { return NULL; } ret = get_state_private(block_group_cache, start, &ptr); if (ret) return NULL; block_group = (struct btrfs_block_group_cache *)(unsigned long)ptr; if (block_group->key.objectid <= bytenr && bytenr < block_group->key.objectid + block_group->key.offset) return block_group; return NULL; } static int block_group_bits(struct btrfs_block_group_cache *cache, u64 bits) { return (cache->flags & bits) == bits; } static int noinline find_search_start(struct btrfs_root *root, struct btrfs_block_group_cache **cache_ret, u64 *start_ret, int num, int data) { int ret; struct btrfs_block_group_cache *cache = *cache_ret; u64 last = *start_ret; u64 start = 0; u64 end = 0; u64 search_start = *start_ret; int wrapped = 0; if (!cache) goto out; again: ret = cache_block_group(root, cache); if (ret) goto out; last = max(search_start, cache->key.objectid); if (cache->ro || !block_group_bits(cache, data)) goto new_group; while(1) { ret = find_first_extent_bit(&root->fs_info->free_space_cache, last, &start, &end, EXTENT_DIRTY); if (ret) { goto new_group; } start = max(last, start); last = end + 1; if (last - start < num) { continue; } if (start + num > cache->key.objectid + cache->key.offset) { goto new_group; } *start_ret = start; return 0; } out: *start_ret = last; cache = btrfs_lookup_block_group(root->fs_info, search_start); if (!cache) { printk("Unable to find block group for %llu\n", (unsigned long long)search_start); WARN_ON(1); } return -ENOSPC; new_group: last = cache->key.objectid + cache->key.offset; wrapped: cache = btrfs_lookup_first_block_group(root->fs_info, last); if (!cache) { if (!wrapped) { wrapped = 1; last = search_start; goto wrapped; } goto out; } *cache_ret = cache; goto again; } static int block_group_state_bits(u64 flags) { int bits = 0; if (flags & BTRFS_BLOCK_GROUP_DATA) bits |= BLOCK_GROUP_DATA; if (flags & BTRFS_BLOCK_GROUP_METADATA) bits |= BLOCK_GROUP_METADATA; if (flags & BTRFS_BLOCK_GROUP_SYSTEM) bits |= BLOCK_GROUP_SYSTEM; return bits; } static struct btrfs_block_group_cache * btrfs_find_block_group(struct btrfs_root *root, struct btrfs_block_group_cache *hint, u64 search_start, int data, int owner) { struct btrfs_block_group_cache *cache; struct extent_io_tree *block_group_cache; struct btrfs_block_group_cache *found_group = NULL; struct btrfs_fs_info *info = root->fs_info; u64 used; u64 last = 0; u64 hint_last; u64 start; u64 end; u64 free_check; u64 ptr; int bit; int ret; int full_search = 0; int factor = 10; block_group_cache = &info->block_group_cache; if (!owner) factor = 10; bit = block_group_state_bits(data); if (search_start) { struct btrfs_block_group_cache *shint; shint = btrfs_lookup_block_group(info, search_start); if (shint && !shint->ro && block_group_bits(shint, data)) { used = btrfs_block_group_used(&shint->item); if (used + shint->pinned < div_factor(shint->key.offset, factor)) { return shint; } } } if (hint && !hint->ro && block_group_bits(hint, data)) { used = btrfs_block_group_used(&hint->item); if (used + hint->pinned < div_factor(hint->key.offset, factor)) { return hint; } last = hint->key.objectid + hint->key.offset; hint_last = last; } else { if (hint) hint_last = max(hint->key.objectid, search_start); else hint_last = search_start; last = hint_last; } again: while(1) { ret = find_first_extent_bit(block_group_cache, last, &start, &end, bit); if (ret) break; ret = get_state_private(block_group_cache, start, &ptr); if (ret) break; cache = (struct btrfs_block_group_cache *)(unsigned long)ptr; last = cache->key.objectid + cache->key.offset; used = btrfs_block_group_used(&cache->item); if (!cache->ro && block_group_bits(cache, data)) { if (full_search) free_check = cache->key.offset; else free_check = div_factor(cache->key.offset, factor); if (used + cache->pinned < free_check) { found_group = cache; goto found; } } cond_resched(); } if (!full_search) { last = search_start; full_search = 1; goto again; } found: return found_group; } /* * Back reference rules. Back refs have three main goals: * * 1) differentiate between all holders of references to an extent so that * when a reference is dropped we can make sure it was a valid reference * before freeing the extent. * * 2) Provide enough information to quickly find the holders of an extent * if we notice a given block is corrupted or bad. * * 3) Make it easy to migrate blocks for FS shrinking or storage pool * maintenance. This is actually the same as #2, but with a slightly * different use case. * * There are two kinds of back refs. The implicit back refs is optimized * for pointers in non-shared tree blocks. For a given pointer in a block, * back refs of this kind provide information about the block's owner tree * and the pointer's key. These information allow us to find the block by * b-tree searching. The full back refs is for pointers in tree blocks not * referenced by their owner trees. The location of tree block is recorded * in the back refs. Actually the full back refs is generic, and can be * used in all cases the implicit back refs is used. The major shortcoming * of the full back refs is its overhead. Every time a tree block gets * COWed, we have to update back refs entry for all pointers in it. * * For a newly allocated tree block, we use implicit back refs for * pointers in it. This means most tree related operations only involve * implicit back refs. For a tree block created in old transaction, the * only way to drop a reference to it is COW it. So we can detect the * event that tree block loses its owner tree's reference and do the * back refs conversion. * * When a tree block is COW'd through a tree, there are four cases: * * The reference count of the block is one and the tree is the block's * owner tree. Nothing to do in this case. * * The reference count of the block is one and the tree is not the * block's owner tree. In this case, full back refs is used for pointers * in the block. Remove these full back refs, add implicit back refs for * every pointers in the new block. * * The reference count of the block is greater than one and the tree is * the block's owner tree. In this case, implicit back refs is used for * pointers in the block. Add full back refs for every pointers in the * block, increase lower level extents' reference counts. The original * implicit back refs are entailed to the new block. * * The reference count of the block is greater than one and the tree is * not the block's owner tree. Add implicit back refs for every pointer in * the new block, increase lower level extents' reference count. * * Back Reference Key composing: * * The key objectid corresponds to the first byte in the extent, * The key type is used to differentiate between types of back refs. * There are different meanings of the key offset for different types * of back refs. * * File extents can be referenced by: * * - multiple snapshots, subvolumes, or different generations in one subvol * - different files inside a single subvolume * - different offsets inside a file (bookend extents in file.c) * * The extent ref structure for the implicit back refs has fields for: * * - Objectid of the subvolume root * - objectid of the file holding the reference * - original offset in the file * - how many bookend extents * * The key offset for the implicit back refs is hash of the first * three fields. * * The extent ref structure for the full back refs has field for: * * - number of pointers in the tree leaf * * The key offset for the implicit back refs is the first byte of * the tree leaf * * When a file extent is allocated, The implicit back refs is used. * the fields are filled in: * * (root_key.objectid, inode objectid, offset in file, 1) * * When a file extent is removed file truncation, we find the * corresponding implicit back refs and check the following fields: * * (btrfs_header_owner(leaf), inode objectid, offset in file) * * Btree extents can be referenced by: * * - Different subvolumes * * Both the implicit back refs and the full back refs for tree blocks * only consist of key. The key offset for the implicit back refs is * objectid of block's owner tree. The key offset for the full back refs * is the first byte of parent block. * * When implicit back refs is used, information about the lowest key and * level of the tree block are required. These information are stored in * tree block info structure. */ #ifdef BTRFS_COMPAT_EXTENT_TREE_V0 static int convert_extent_item_v0(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, u64 owner, u32 extra_size) { struct btrfs_extent_item *item; struct btrfs_extent_item_v0 *ei0; struct btrfs_extent_ref_v0 *ref0; struct btrfs_tree_block_info *bi; struct extent_buffer *leaf; struct btrfs_key key; struct btrfs_key found_key; u32 new_size = sizeof(*item); u64 refs; int ret; leaf = path->nodes[0]; BUG_ON(btrfs_item_size_nr(leaf, path->slots[0]) != sizeof(*ei0)); btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); ei0 = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_item_v0); refs = btrfs_extent_refs_v0(leaf, ei0); if (owner == (u64)-1) { while (1) { if (path->slots[0] >= btrfs_header_nritems(leaf)) { ret = btrfs_next_leaf(root, path); if (ret < 0) return ret; BUG_ON(ret > 0); leaf = path->nodes[0]; } btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); BUG_ON(key.objectid != found_key.objectid); if (found_key.type != BTRFS_EXTENT_REF_V0_KEY) { path->slots[0]++; continue; } ref0 = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_ref_v0); owner = btrfs_ref_objectid_v0(leaf, ref0); break; } } btrfs_release_path(path); if (owner < BTRFS_FIRST_FREE_OBJECTID) new_size += sizeof(*bi); new_size -= sizeof(*ei0); ret = btrfs_search_slot(trans, root, &key, path, new_size, 1); if (ret < 0) return ret; BUG_ON(ret); ret = btrfs_extend_item(trans, root, path, new_size); BUG_ON(ret); leaf = path->nodes[0]; item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_item); btrfs_set_extent_refs(leaf, item, refs); /* FIXME: get real generation */ btrfs_set_extent_generation(leaf, item, 0); if (owner < BTRFS_FIRST_FREE_OBJECTID) { btrfs_set_extent_flags(leaf, item, BTRFS_EXTENT_FLAG_TREE_BLOCK | BTRFS_BLOCK_FLAG_FULL_BACKREF); bi = (struct btrfs_tree_block_info *)(item + 1); /* FIXME: get first key of the block */ memset_extent_buffer(leaf, 0, (unsigned long)bi, sizeof(*bi)); btrfs_set_tree_block_level(leaf, bi, (int)owner); } else { btrfs_set_extent_flags(leaf, item, BTRFS_EXTENT_FLAG_DATA); } btrfs_mark_buffer_dirty(leaf); return 0; } #endif static u64 hash_extent_data_ref(u64 root_objectid, u64 owner, u64 offset) { u32 high_crc = ~(u32)0; u32 low_crc = ~(u32)0; __le64 lenum; lenum = cpu_to_le64(root_objectid); high_crc = btrfs_crc32c(high_crc, &lenum, sizeof(lenum)); lenum = cpu_to_le64(owner); low_crc = btrfs_crc32c(low_crc, &lenum, sizeof(lenum)); lenum = cpu_to_le64(offset); low_crc = btrfs_crc32c(low_crc, &lenum, sizeof(lenum)); return ((u64)high_crc << 31) ^ (u64)low_crc; } static u64 hash_extent_data_ref_item(struct extent_buffer *leaf, struct btrfs_extent_data_ref *ref) { return hash_extent_data_ref(btrfs_extent_data_ref_root(leaf, ref), btrfs_extent_data_ref_objectid(leaf, ref), btrfs_extent_data_ref_offset(leaf, ref)); } static int match_extent_data_ref(struct extent_buffer *leaf, struct btrfs_extent_data_ref *ref, u64 root_objectid, u64 owner, u64 offset) { if (btrfs_extent_data_ref_root(leaf, ref) != root_objectid || btrfs_extent_data_ref_objectid(leaf, ref) != owner || btrfs_extent_data_ref_offset(leaf, ref) != offset) return 0; return 1; } static noinline int lookup_extent_data_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, u64 bytenr, u64 parent, u64 root_objectid, u64 owner, u64 offset) { struct btrfs_key key; struct btrfs_extent_data_ref *ref; struct extent_buffer *leaf; u32 nritems; int ret; int recow; int err = -ENOENT; key.objectid = bytenr; if (parent) { key.type = BTRFS_SHARED_DATA_REF_KEY; key.offset = parent; } else { key.type = BTRFS_EXTENT_DATA_REF_KEY; key.offset = hash_extent_data_ref(root_objectid, owner, offset); } again: recow = 0; ret = btrfs_search_slot(trans, root, &key, path, -1, 1); if (ret < 0) { err = ret; goto fail; } if (parent) { if (!ret) return 0; #ifdef BTRFS_COMPAT_EXTENT_TREE_V0 key.type = BTRFS_EXTENT_REF_V0_KEY; btrfs_release_path(path); ret = btrfs_search_slot(trans, root, &key, path, -1, 1); if (ret < 0) { err = ret; goto fail; } if (!ret) return 0; #endif goto fail; } leaf = path->nodes[0]; nritems = btrfs_header_nritems(leaf); while (1) { if (path->slots[0] >= nritems) { ret = btrfs_next_leaf(root, path); if (ret < 0) err = ret; if (ret) goto fail; leaf = path->nodes[0]; nritems = btrfs_header_nritems(leaf); recow = 1; } btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); if (key.objectid != bytenr || key.type != BTRFS_EXTENT_DATA_REF_KEY) goto fail; ref = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_data_ref); if (match_extent_data_ref(leaf, ref, root_objectid, owner, offset)) { if (recow) { btrfs_release_path(path); goto again; } err = 0; break; } path->slots[0]++; } fail: return err; } static noinline int insert_extent_data_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, u64 bytenr, u64 parent, u64 root_objectid, u64 owner, u64 offset, int refs_to_add) { struct btrfs_key key; struct extent_buffer *leaf; u32 size; u32 num_refs; int ret; key.objectid = bytenr; if (parent) { key.type = BTRFS_SHARED_DATA_REF_KEY; key.offset = parent; size = sizeof(struct btrfs_shared_data_ref); } else { key.type = BTRFS_EXTENT_DATA_REF_KEY; key.offset = hash_extent_data_ref(root_objectid, owner, offset); size = sizeof(struct btrfs_extent_data_ref); } ret = btrfs_insert_empty_item(trans, root, path, &key, size); if (ret && ret != -EEXIST) goto fail; leaf = path->nodes[0]; if (parent) { struct btrfs_shared_data_ref *ref; ref = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_shared_data_ref); if (ret == 0) { btrfs_set_shared_data_ref_count(leaf, ref, refs_to_add); } else { num_refs = btrfs_shared_data_ref_count(leaf, ref); num_refs += refs_to_add; btrfs_set_shared_data_ref_count(leaf, ref, num_refs); } } else { struct btrfs_extent_data_ref *ref; while (ret == -EEXIST) { ref = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_data_ref); if (match_extent_data_ref(leaf, ref, root_objectid, owner, offset)) break; btrfs_release_path(path); key.offset++; ret = btrfs_insert_empty_item(trans, root, path, &key, size); if (ret && ret != -EEXIST) goto fail; leaf = path->nodes[0]; } ref = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_data_ref); if (ret == 0) { btrfs_set_extent_data_ref_root(leaf, ref, root_objectid); btrfs_set_extent_data_ref_objectid(leaf, ref, owner); btrfs_set_extent_data_ref_offset(leaf, ref, offset); btrfs_set_extent_data_ref_count(leaf, ref, refs_to_add); } else { num_refs = btrfs_extent_data_ref_count(leaf, ref); num_refs += refs_to_add; btrfs_set_extent_data_ref_count(leaf, ref, num_refs); } } btrfs_mark_buffer_dirty(leaf); ret = 0; fail: btrfs_release_path(path); return ret; } static noinline int remove_extent_data_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, int refs_to_drop) { struct btrfs_key key; struct btrfs_extent_data_ref *ref1 = NULL; struct btrfs_shared_data_ref *ref2 = NULL; struct extent_buffer *leaf; u32 num_refs = 0; int ret = 0; leaf = path->nodes[0]; btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); if (key.type == BTRFS_EXTENT_DATA_REF_KEY) { ref1 = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_data_ref); num_refs = btrfs_extent_data_ref_count(leaf, ref1); } else if (key.type == BTRFS_SHARED_DATA_REF_KEY) { ref2 = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_shared_data_ref); num_refs = btrfs_shared_data_ref_count(leaf, ref2); #ifdef BTRFS_COMPAT_EXTENT_TREE_V0 } else if (key.type == BTRFS_EXTENT_REF_V0_KEY) { struct btrfs_extent_ref_v0 *ref0; ref0 = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_ref_v0); num_refs = btrfs_ref_count_v0(leaf, ref0); #endif } else { BUG(); } BUG_ON(num_refs < refs_to_drop); num_refs -= refs_to_drop; if (num_refs == 0) { ret = btrfs_del_item(trans, root, path); } else { if (key.type == BTRFS_EXTENT_DATA_REF_KEY) btrfs_set_extent_data_ref_count(leaf, ref1, num_refs); else if (key.type == BTRFS_SHARED_DATA_REF_KEY) btrfs_set_shared_data_ref_count(leaf, ref2, num_refs); #ifdef BTRFS_COMPAT_EXTENT_TREE_V0 else { struct btrfs_extent_ref_v0 *ref0; ref0 = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_ref_v0); btrfs_set_ref_count_v0(leaf, ref0, num_refs); } #endif btrfs_mark_buffer_dirty(leaf); } return ret; } static noinline u32 extent_data_ref_count(struct btrfs_root *root, struct btrfs_path *path, struct btrfs_extent_inline_ref *iref) { struct btrfs_key key; struct extent_buffer *leaf; struct btrfs_extent_data_ref *ref1; struct btrfs_shared_data_ref *ref2; u32 num_refs = 0; leaf = path->nodes[0]; btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); if (iref) { if (btrfs_extent_inline_ref_type(leaf, iref) == BTRFS_EXTENT_DATA_REF_KEY) { ref1 = (struct btrfs_extent_data_ref *)(&iref->offset); num_refs = btrfs_extent_data_ref_count(leaf, ref1); } else { ref2 = (struct btrfs_shared_data_ref *)(iref + 1); num_refs = btrfs_shared_data_ref_count(leaf, ref2); } } else if (key.type == BTRFS_EXTENT_DATA_REF_KEY) { ref1 = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_data_ref); num_refs = btrfs_extent_data_ref_count(leaf, ref1); } else if (key.type == BTRFS_SHARED_DATA_REF_KEY) { ref2 = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_shared_data_ref); num_refs = btrfs_shared_data_ref_count(leaf, ref2); #ifdef BTRFS_COMPAT_EXTENT_TREE_V0 } else if (key.type == BTRFS_EXTENT_REF_V0_KEY) { struct btrfs_extent_ref_v0 *ref0; ref0 = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_ref_v0); num_refs = btrfs_ref_count_v0(leaf, ref0); #endif } else { BUG(); } return num_refs; } static noinline int lookup_tree_block_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, u64 bytenr, u64 parent, u64 root_objectid) { struct btrfs_key key; int ret; key.objectid = bytenr; if (parent) { key.type = BTRFS_SHARED_BLOCK_REF_KEY; key.offset = parent; } else { key.type = BTRFS_TREE_BLOCK_REF_KEY; key.offset = root_objectid; } ret = btrfs_search_slot(trans, root, &key, path, -1, 1); if (ret > 0) ret = -ENOENT; #ifdef BTRFS_COMPAT_EXTENT_TREE_V0 if (ret == -ENOENT && parent) { btrfs_release_path(path); key.type = BTRFS_EXTENT_REF_V0_KEY; ret = btrfs_search_slot(trans, root, &key, path, -1, 1); if (ret > 0) ret = -ENOENT; } #endif return ret; } static noinline int insert_tree_block_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, u64 bytenr, u64 parent, u64 root_objectid) { struct btrfs_key key; int ret; key.objectid = bytenr; if (parent) { key.type = BTRFS_SHARED_BLOCK_REF_KEY; key.offset = parent; } else { key.type = BTRFS_TREE_BLOCK_REF_KEY; key.offset = root_objectid; } ret = btrfs_insert_empty_item(trans, root, path, &key, 0); btrfs_release_path(path); return ret; } static inline int extent_ref_type(u64 parent, u64 owner) { int type; if (owner < BTRFS_FIRST_FREE_OBJECTID) { if (parent > 0) type = BTRFS_SHARED_BLOCK_REF_KEY; else type = BTRFS_TREE_BLOCK_REF_KEY; } else { if (parent > 0) type = BTRFS_SHARED_DATA_REF_KEY; else type = BTRFS_EXTENT_DATA_REF_KEY; } return type; } static int lookup_inline_extent_backref(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, struct btrfs_extent_inline_ref **ref_ret, u64 bytenr, u64 num_bytes, u64 parent, u64 root_objectid, u64 owner, u64 offset, int insert) { struct btrfs_key key; struct extent_buffer *leaf; struct btrfs_extent_item *ei; struct btrfs_extent_inline_ref *iref; u64 flags; u32 item_size; unsigned long ptr; unsigned long end; int extra_size; int type; int want; int ret; int err = 0; int skinny_metadata = btrfs_fs_incompat(root->fs_info, BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA); key.objectid = bytenr; key.type = BTRFS_EXTENT_ITEM_KEY; key.offset = num_bytes; want = extent_ref_type(parent, owner); if (insert) extra_size = btrfs_extent_inline_ref_size(want); else extra_size = -1; if (owner < BTRFS_FIRST_FREE_OBJECTID && skinny_metadata) { skinny_metadata = 1; key.type = BTRFS_METADATA_ITEM_KEY; key.offset = owner; } else if (skinny_metadata) { skinny_metadata = 0; } again: ret = btrfs_search_slot(trans, root, &key, path, extra_size, 1); if (ret < 0) { err = ret; goto out; } /* * We may be a newly converted file system which still has the old fat * extent entries for metadata, so try and see if we have one of those. */ if (ret > 0 && skinny_metadata) { skinny_metadata = 0; if (path->slots[0]) { path->slots[0]--; btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); if (key.objectid == bytenr && key.type == BTRFS_EXTENT_ITEM_KEY && key.offset == num_bytes) ret = 0; } if (ret) { key.type = BTRFS_EXTENT_ITEM_KEY; key.offset = num_bytes; btrfs_release_path(path); goto again; } } if (ret) { printf("Failed to find [%llu, %u, %llu]\n", key.objectid, key.type, key.offset); return -ENOENT; } BUG_ON(ret); leaf = path->nodes[0]; item_size = btrfs_item_size_nr(leaf, path->slots[0]); #ifdef BTRFS_COMPAT_EXTENT_TREE_V0 if (item_size < sizeof(*ei)) { if (!insert) { err = -ENOENT; goto out; } ret = convert_extent_item_v0(trans, root, path, owner, extra_size); if (ret < 0) { err = ret; goto out; } leaf = path->nodes[0]; item_size = btrfs_item_size_nr(leaf, path->slots[0]); } #endif if (item_size < sizeof(*ei)) { printf("Size is %u, needs to be %u, slot %d\n", (unsigned)item_size, (unsigned)sizeof(*ei), path->slots[0]); btrfs_print_leaf(root, leaf); return -EINVAL; } BUG_ON(item_size < sizeof(*ei)); ei = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_item); flags = btrfs_extent_flags(leaf, ei); ptr = (unsigned long)(ei + 1); end = (unsigned long)ei + item_size; if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK && !skinny_metadata) { ptr += sizeof(struct btrfs_tree_block_info); BUG_ON(ptr > end); } else if (!(flags & BTRFS_EXTENT_FLAG_TREE_BLOCK)) { if (!(flags & BTRFS_EXTENT_FLAG_DATA)) { return -EIO; } } err = -ENOENT; while (1) { if (ptr >= end) { WARN_ON(ptr > end); break; } iref = (struct btrfs_extent_inline_ref *)ptr; type = btrfs_extent_inline_ref_type(leaf, iref); if (want < type) break; if (want > type) { ptr += btrfs_extent_inline_ref_size(type); continue; } if (type == BTRFS_EXTENT_DATA_REF_KEY) { struct btrfs_extent_data_ref *dref; dref = (struct btrfs_extent_data_ref *)(&iref->offset); if (match_extent_data_ref(leaf, dref, root_objectid, owner, offset)) { err = 0; break; } if (hash_extent_data_ref_item(leaf, dref) < hash_extent_data_ref(root_objectid, owner, offset)) break; } else { u64 ref_offset; ref_offset = btrfs_extent_inline_ref_offset(leaf, iref); if (parent > 0) { if (parent == ref_offset) { err = 0; break; } if (ref_offset < parent) break; } else { if (root_objectid == ref_offset) { err = 0; break; } if (ref_offset < root_objectid) break; } } ptr += btrfs_extent_inline_ref_size(type); } if (err == -ENOENT && insert) { if (item_size + extra_size >= BTRFS_MAX_EXTENT_ITEM_SIZE(root)) { err = -EAGAIN; goto out; } /* * To add new inline back ref, we have to make sure * there is no corresponding back ref item. * For simplicity, we just do not add new inline back * ref if there is any back ref item. */ if (find_next_key(path, &key) == 0 && key.objectid == bytenr && key.type < BTRFS_BLOCK_GROUP_ITEM_KEY) { err = -EAGAIN; goto out; } } *ref_ret = (struct btrfs_extent_inline_ref *)ptr; out: return err; } static int setup_inline_extent_backref(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, struct btrfs_extent_inline_ref *iref, u64 parent, u64 root_objectid, u64 owner, u64 offset, int refs_to_add) { struct extent_buffer *leaf; struct btrfs_extent_item *ei; unsigned long ptr; unsigned long end; unsigned long item_offset; u64 refs; int size; int type; int ret; leaf = path->nodes[0]; ei = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_item); item_offset = (unsigned long)iref - (unsigned long)ei; type = extent_ref_type(parent, owner); size = btrfs_extent_inline_ref_size(type); ret = btrfs_extend_item(trans, root, path, size); BUG_ON(ret); ei = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_item); refs = btrfs_extent_refs(leaf, ei); refs += refs_to_add; btrfs_set_extent_refs(leaf, ei, refs); ptr = (unsigned long)ei + item_offset; end = (unsigned long)ei + btrfs_item_size_nr(leaf, path->slots[0]); if (ptr < end - size) memmove_extent_buffer(leaf, ptr + size, ptr, end - size - ptr); iref = (struct btrfs_extent_inline_ref *)ptr; btrfs_set_extent_inline_ref_type(leaf, iref, type); if (type == BTRFS_EXTENT_DATA_REF_KEY) { struct btrfs_extent_data_ref *dref; dref = (struct btrfs_extent_data_ref *)(&iref->offset); btrfs_set_extent_data_ref_root(leaf, dref, root_objectid); btrfs_set_extent_data_ref_objectid(leaf, dref, owner); btrfs_set_extent_data_ref_offset(leaf, dref, offset); btrfs_set_extent_data_ref_count(leaf, dref, refs_to_add); } else if (type == BTRFS_SHARED_DATA_REF_KEY) { struct btrfs_shared_data_ref *sref; sref = (struct btrfs_shared_data_ref *)(iref + 1); btrfs_set_shared_data_ref_count(leaf, sref, refs_to_add); btrfs_set_extent_inline_ref_offset(leaf, iref, parent); } else if (type == BTRFS_SHARED_BLOCK_REF_KEY) { btrfs_set_extent_inline_ref_offset(leaf, iref, parent); } else { btrfs_set_extent_inline_ref_offset(leaf, iref, root_objectid); } btrfs_mark_buffer_dirty(leaf); return 0; } static int lookup_extent_backref(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, struct btrfs_extent_inline_ref **ref_ret, u64 bytenr, u64 num_bytes, u64 parent, u64 root_objectid, u64 owner, u64 offset) { int ret; ret = lookup_inline_extent_backref(trans, root, path, ref_ret, bytenr, num_bytes, parent, root_objectid, owner, offset, 0); if (ret != -ENOENT) return ret; btrfs_release_path(path); *ref_ret = NULL; if (owner < BTRFS_FIRST_FREE_OBJECTID) { ret = lookup_tree_block_ref(trans, root, path, bytenr, parent, root_objectid); } else { ret = lookup_extent_data_ref(trans, root, path, bytenr, parent, root_objectid, owner, offset); } return ret; } static int update_inline_extent_backref(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, struct btrfs_extent_inline_ref *iref, int refs_to_mod) { struct extent_buffer *leaf; struct btrfs_extent_item *ei; struct btrfs_extent_data_ref *dref = NULL; struct btrfs_shared_data_ref *sref = NULL; unsigned long ptr; unsigned long end; u32 item_size; int size; int type; int ret; u64 refs; leaf = path->nodes[0]; ei = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_item); refs = btrfs_extent_refs(leaf, ei); WARN_ON(refs_to_mod < 0 && refs + refs_to_mod <= 0); refs += refs_to_mod; btrfs_set_extent_refs(leaf, ei, refs); type = btrfs_extent_inline_ref_type(leaf, iref); if (type == BTRFS_EXTENT_DATA_REF_KEY) { dref = (struct btrfs_extent_data_ref *)(&iref->offset); refs = btrfs_extent_data_ref_count(leaf, dref); } else if (type == BTRFS_SHARED_DATA_REF_KEY) { sref = (struct btrfs_shared_data_ref *)(iref + 1); refs = btrfs_shared_data_ref_count(leaf, sref); } else { refs = 1; BUG_ON(refs_to_mod != -1); } BUG_ON(refs_to_mod < 0 && refs < -refs_to_mod); refs += refs_to_mod; if (refs > 0) { if (type == BTRFS_EXTENT_DATA_REF_KEY) btrfs_set_extent_data_ref_count(leaf, dref, refs); else btrfs_set_shared_data_ref_count(leaf, sref, refs); } else { size = btrfs_extent_inline_ref_size(type); item_size = btrfs_item_size_nr(leaf, path->slots[0]); ptr = (unsigned long)iref; end = (unsigned long)ei + item_size; if (ptr + size < end) memmove_extent_buffer(leaf, ptr, ptr + size, end - ptr - size); item_size -= size; ret = btrfs_truncate_item(trans, root, path, item_size, 1); BUG_ON(ret); } btrfs_mark_buffer_dirty(leaf); return 0; } static int insert_inline_extent_backref(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, u64 bytenr, u64 num_bytes, u64 parent, u64 root_objectid, u64 owner, u64 offset, int refs_to_add) { struct btrfs_extent_inline_ref *iref; int ret; ret = lookup_inline_extent_backref(trans, root, path, &iref, bytenr, num_bytes, parent, root_objectid, owner, offset, 1); if (ret == 0) { BUG_ON(owner < BTRFS_FIRST_FREE_OBJECTID); ret = update_inline_extent_backref(trans, root, path, iref, refs_to_add); } else if (ret == -ENOENT) { ret = setup_inline_extent_backref(trans, root, path, iref, parent, root_objectid, owner, offset, refs_to_add); } return ret; } static int insert_extent_backref(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, u64 bytenr, u64 parent, u64 root_objectid, u64 owner, u64 offset, int refs_to_add) { int ret; if (owner >= BTRFS_FIRST_FREE_OBJECTID) { ret = insert_extent_data_ref(trans, root, path, bytenr, parent, root_objectid, owner, offset, refs_to_add); } else { BUG_ON(refs_to_add != 1); ret = insert_tree_block_ref(trans, root, path, bytenr, parent, root_objectid); } return ret; } static int remove_extent_backref(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, struct btrfs_extent_inline_ref *iref, int refs_to_drop, int is_data) { int ret; BUG_ON(!is_data && refs_to_drop != 1); if (iref) { ret = update_inline_extent_backref(trans, root, path, iref, -refs_to_drop); } else if (is_data) { ret = remove_extent_data_ref(trans, root, path, refs_to_drop); } else { ret = btrfs_del_item(trans, root, path); } return ret; } int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 bytenr, u64 num_bytes, u64 parent, u64 root_objectid, u64 owner, u64 offset) { struct btrfs_path *path; struct extent_buffer *leaf; struct btrfs_extent_item *item; u64 refs; int ret; int err = 0; path = btrfs_alloc_path(); if (!path) return -ENOMEM; path->reada = 1; ret = insert_inline_extent_backref(trans, root->fs_info->extent_root, path, bytenr, num_bytes, parent, root_objectid, owner, offset, 1); if (ret == 0) goto out; if (ret != -EAGAIN) { err = ret; goto out; } leaf = path->nodes[0]; item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_item); refs = btrfs_extent_refs(leaf, item); btrfs_set_extent_refs(leaf, item, refs + 1); btrfs_mark_buffer_dirty(leaf); btrfs_release_path(path); path->reada = 1; /* now insert the actual backref */ ret = insert_extent_backref(trans, root->fs_info->extent_root, path, bytenr, parent, root_objectid, owner, offset, 1); if (ret) err = ret; out: btrfs_free_path(path); finish_current_insert(trans, root->fs_info->extent_root); del_pending_extents(trans, root->fs_info->extent_root); BUG_ON(err); return err; } int btrfs_extent_post_op(struct btrfs_trans_handle *trans, struct btrfs_root *root) { finish_current_insert(trans, root->fs_info->extent_root); del_pending_extents(trans, root->fs_info->extent_root); return 0; } int btrfs_lookup_extent_info(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 bytenr, u64 offset, int metadata, u64 *refs, u64 *flags) { struct btrfs_path *path; int ret; struct btrfs_key key; struct extent_buffer *l; struct btrfs_extent_item *item; u32 item_size; u64 num_refs; u64 extent_flags; if (metadata && !btrfs_fs_incompat(root->fs_info, BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA)) { offset = root->leafsize; metadata = 0; } path = btrfs_alloc_path(); if (!path) return -ENOMEM; path->reada = 1; key.objectid = bytenr; key.offset = offset; if (metadata) key.type = BTRFS_METADATA_ITEM_KEY; else key.type = BTRFS_EXTENT_ITEM_KEY; again: ret = btrfs_search_slot(trans, root->fs_info->extent_root, &key, path, 0, 0); if (ret < 0) goto out; /* * Deal with the fact that we may have mixed SKINNY and normal refs. If * we didn't find what we wanted check and see if we have a normal ref * right next to us, or re-search if we are on the edge of the leaf just * to make sure. */ if (ret > 0 && metadata) { if (path->slots[0]) { path->slots[0]--; btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); if (key.objectid == bytenr && key.type == BTRFS_EXTENT_ITEM_KEY && key.offset == root->leafsize) ret = 0; } if (ret) { btrfs_release_path(path); key.type = BTRFS_EXTENT_ITEM_KEY; key.offset = root->leafsize; metadata = 0; goto again; } } if (ret != 0) { ret = -EIO; goto out; } l = path->nodes[0]; item_size = btrfs_item_size_nr(l, path->slots[0]); if (item_size >= sizeof(*item)) { item = btrfs_item_ptr(l, path->slots[0], struct btrfs_extent_item); num_refs = btrfs_extent_refs(l, item); extent_flags = btrfs_extent_flags(l, item); } else { #ifdef BTRFS_COMPAT_EXTENT_TREE_V0 struct btrfs_extent_item_v0 *ei0; BUG_ON(item_size != sizeof(*ei0)); ei0 = btrfs_item_ptr(l, path->slots[0], struct btrfs_extent_item_v0); num_refs = btrfs_extent_refs_v0(l, ei0); /* FIXME: this isn't correct for data */ extent_flags = BTRFS_BLOCK_FLAG_FULL_BACKREF; #else BUG(); #endif } item = btrfs_item_ptr(l, path->slots[0], struct btrfs_extent_item); if (refs) *refs = num_refs; if (flags) *flags = extent_flags; out: btrfs_free_path(path); return ret; } int btrfs_set_block_flags(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 bytenr, int level, u64 flags) { struct btrfs_path *path; int ret; struct btrfs_key key; struct extent_buffer *l; struct btrfs_extent_item *item; u32 item_size; int skinny_metadata = btrfs_fs_incompat(root->fs_info, BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA); path = btrfs_alloc_path(); if (!path) return -ENOMEM; path->reada = 1; key.objectid = bytenr; if (skinny_metadata) { key.offset = level; key.type = BTRFS_METADATA_ITEM_KEY; } else { key.offset = root->leafsize; key.type = BTRFS_EXTENT_ITEM_KEY; } again: ret = btrfs_search_slot(trans, root->fs_info->extent_root, &key, path, 0, 0); if (ret < 0) goto out; if (ret > 0 && skinny_metadata) { skinny_metadata = 0; if (path->slots[0]) { path->slots[0]--; btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); if (key.objectid == bytenr && key.offset == root->leafsize && key.type == BTRFS_EXTENT_ITEM_KEY) ret = 0; } if (ret) { btrfs_release_path(path); key.offset = root->leafsize; key.type = BTRFS_EXTENT_ITEM_KEY; goto again; } } if (ret != 0) { btrfs_print_leaf(root, path->nodes[0]); printk("failed to find block number %Lu\n", (unsigned long long)bytenr); BUG(); } l = path->nodes[0]; item_size = btrfs_item_size_nr(l, path->slots[0]); #ifdef BTRFS_COMPAT_EXTENT_TREE_V0 if (item_size < sizeof(*item)) { ret = convert_extent_item_v0(trans, root->fs_info->extent_root, path, (u64)-1, 0); if (ret < 0) goto out; l = path->nodes[0]; item_size = btrfs_item_size_nr(l, path->slots[0]); } #endif BUG_ON(item_size < sizeof(*item)); item = btrfs_item_ptr(l, path->slots[0], struct btrfs_extent_item); flags |= btrfs_extent_flags(l, item); btrfs_set_extent_flags(l, item, flags); out: btrfs_free_path(path); finish_current_insert(trans, root->fs_info->extent_root); del_pending_extents(trans, root->fs_info->extent_root); return ret; } static int __btrfs_mod_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct extent_buffer *buf, int record_parent, int inc) { u64 bytenr; u64 num_bytes; u64 parent; u64 ref_root; u32 nritems; struct btrfs_key key; struct btrfs_file_extent_item *fi; int i; int level; int ret = 0; int (*process_func)(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64, u64, u64, u64, u64, u64); ref_root = btrfs_header_owner(buf); nritems = btrfs_header_nritems(buf); level = btrfs_header_level(buf); if (!root->ref_cows && level == 0) return 0; if (inc) process_func = btrfs_inc_extent_ref; else process_func = btrfs_free_extent; if (record_parent) parent = buf->start; else parent = 0; for (i = 0; i < nritems; i++) { cond_resched(); if (level == 0) { btrfs_item_key_to_cpu(buf, &key, i); if (btrfs_key_type(&key) != BTRFS_EXTENT_DATA_KEY) continue; fi = btrfs_item_ptr(buf, i, struct btrfs_file_extent_item); if (btrfs_file_extent_type(buf, fi) == BTRFS_FILE_EXTENT_INLINE) continue; bytenr = btrfs_file_extent_disk_bytenr(buf, fi); if (bytenr == 0) continue; num_bytes = btrfs_file_extent_disk_num_bytes(buf, fi); key.offset -= btrfs_file_extent_offset(buf, fi); ret = process_func(trans, root, bytenr, num_bytes, parent, ref_root, key.objectid, key.offset); if (ret) { WARN_ON(1); goto fail; } } else { bytenr = btrfs_node_blockptr(buf, i); num_bytes = btrfs_level_size(root, level - 1); ret = process_func(trans, root, bytenr, num_bytes, parent, ref_root, level - 1, 0); if (ret) { WARN_ON(1); goto fail; } } } return 0; fail: WARN_ON(1); return ret; } int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct extent_buffer *buf, int record_parent) { return __btrfs_mod_ref(trans, root, buf, record_parent, 1); } int btrfs_dec_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct extent_buffer *buf, int record_parent) { return __btrfs_mod_ref(trans, root, buf, record_parent, 0); } static int write_one_cache_group(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, struct btrfs_block_group_cache *cache) { int ret; int pending_ret; struct btrfs_root *extent_root = root->fs_info->extent_root; unsigned long bi; struct extent_buffer *leaf; ret = btrfs_search_slot(trans, extent_root, &cache->key, path, 0, 1); if (ret < 0) goto fail; BUG_ON(ret); leaf = path->nodes[0]; bi = btrfs_item_ptr_offset(leaf, path->slots[0]); write_extent_buffer(leaf, &cache->item, bi, sizeof(cache->item)); btrfs_mark_buffer_dirty(leaf); btrfs_release_path(path); fail: finish_current_insert(trans, extent_root); pending_ret = del_pending_extents(trans, extent_root); if (ret) return ret; if (pending_ret) return pending_ret; return 0; } int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans, struct btrfs_root *root) { struct extent_io_tree *block_group_cache; struct btrfs_block_group_cache *cache; int ret; struct btrfs_path *path; u64 last = 0; u64 start; u64 end; u64 ptr; block_group_cache = &root->fs_info->block_group_cache; path = btrfs_alloc_path(); if (!path) return -ENOMEM; while(1) { ret = find_first_extent_bit(block_group_cache, last, &start, &end, BLOCK_GROUP_DIRTY); if (ret) { if (last == 0) break; last = 0; continue; } last = end + 1; ret = get_state_private(block_group_cache, start, &ptr); BUG_ON(ret); clear_extent_bits(block_group_cache, start, end, BLOCK_GROUP_DIRTY, GFP_NOFS); cache = (struct btrfs_block_group_cache *)(unsigned long)ptr; ret = write_one_cache_group(trans, root, path, cache); } btrfs_free_path(path); return 0; } static struct btrfs_space_info *__find_space_info(struct btrfs_fs_info *info, u64 flags) { struct list_head *head = &info->space_info; struct list_head *cur; struct btrfs_space_info *found; list_for_each(cur, head) { found = list_entry(cur, struct btrfs_space_info, list); if (found->flags & flags) return found; } return NULL; } static int update_space_info(struct btrfs_fs_info *info, u64 flags, u64 total_bytes, u64 bytes_used, struct btrfs_space_info **space_info) { struct btrfs_space_info *found; found = __find_space_info(info, flags); if (found) { found->total_bytes += total_bytes; found->bytes_used += bytes_used; if (found->total_bytes < found->bytes_used) { fprintf(stderr, "warning, bad space info total_bytes " "%llu used %llu\n", (unsigned long long)found->total_bytes, (unsigned long long)found->bytes_used); } *space_info = found; return 0; } found = kmalloc(sizeof(*found), GFP_NOFS); if (!found) return -ENOMEM; list_add(&found->list, &info->space_info); found->flags = flags; found->total_bytes = total_bytes; found->bytes_used = bytes_used; found->bytes_pinned = 0; found->full = 0; *space_info = found; return 0; } static void set_avail_alloc_bits(struct btrfs_fs_info *fs_info, u64 flags) { u64 extra_flags = flags & (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID10 | BTRFS_BLOCK_GROUP_RAID5 | BTRFS_BLOCK_GROUP_RAID6 | BTRFS_BLOCK_GROUP_DUP); if (extra_flags) { if (flags & BTRFS_BLOCK_GROUP_DATA) fs_info->avail_data_alloc_bits |= extra_flags; if (flags & BTRFS_BLOCK_GROUP_METADATA) fs_info->avail_metadata_alloc_bits |= extra_flags; if (flags & BTRFS_BLOCK_GROUP_SYSTEM) fs_info->avail_system_alloc_bits |= extra_flags; } } static int do_chunk_alloc(struct btrfs_trans_handle *trans, struct btrfs_root *extent_root, u64 alloc_bytes, u64 flags) { struct btrfs_space_info *space_info; u64 thresh; u64 start; u64 num_bytes; int ret; space_info = __find_space_info(extent_root->fs_info, flags); if (!space_info) { ret = update_space_info(extent_root->fs_info, flags, 0, 0, &space_info); BUG_ON(ret); } BUG_ON(!space_info); if (space_info->full) return 0; thresh = div_factor(space_info->total_bytes, 7); if ((space_info->bytes_used + space_info->bytes_pinned + alloc_bytes) < thresh) return 0; ret = btrfs_alloc_chunk(trans, extent_root, &start, &num_bytes, space_info->flags); if (ret == -ENOSPC) { space_info->full = 1; return 0; } BUG_ON(ret); ret = btrfs_make_block_group(trans, extent_root, 0, space_info->flags, BTRFS_FIRST_CHUNK_TREE_OBJECTID, start, num_bytes); BUG_ON(ret); return 0; } static int update_block_group(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 bytenr, u64 num_bytes, int alloc, int mark_free) { struct btrfs_block_group_cache *cache; struct btrfs_fs_info *info = root->fs_info; u64 total = num_bytes; u64 old_val; u64 byte_in_group; u64 start; u64 end; /* block accounting for super block */ old_val = btrfs_super_bytes_used(info->super_copy); if (alloc) old_val += num_bytes; else old_val -= num_bytes; btrfs_set_super_bytes_used(info->super_copy, old_val); /* block accounting for root item */ old_val = btrfs_root_used(&root->root_item); if (alloc) old_val += num_bytes; else old_val -= num_bytes; btrfs_set_root_used(&root->root_item, old_val); while(total) { cache = btrfs_lookup_block_group(info, bytenr); if (!cache) { return -1; } byte_in_group = bytenr - cache->key.objectid; WARN_ON(byte_in_group > cache->key.offset); start = cache->key.objectid; end = start + cache->key.offset - 1; set_extent_bits(&info->block_group_cache, start, end, BLOCK_GROUP_DIRTY, GFP_NOFS); old_val = btrfs_block_group_used(&cache->item); num_bytes = min(total, cache->key.offset - byte_in_group); if (alloc) { old_val += num_bytes; cache->space_info->bytes_used += num_bytes; } else { old_val -= num_bytes; cache->space_info->bytes_used -= num_bytes; if (mark_free) { set_extent_dirty(&info->free_space_cache, bytenr, bytenr + num_bytes - 1, GFP_NOFS); } } btrfs_set_block_group_used(&cache->item, old_val); total -= num_bytes; bytenr += num_bytes; } return 0; } static int update_pinned_extents(struct btrfs_root *root, u64 bytenr, u64 num, int pin) { u64 len; struct btrfs_block_group_cache *cache; struct btrfs_fs_info *fs_info = root->fs_info; if (pin) { set_extent_dirty(&fs_info->pinned_extents, bytenr, bytenr + num - 1, GFP_NOFS); } else { clear_extent_dirty(&fs_info->pinned_extents, bytenr, bytenr + num - 1, GFP_NOFS); } while (num > 0) { cache = btrfs_lookup_block_group(fs_info, bytenr); if (!cache) { len = min((u64)root->sectorsize, num); goto next; } WARN_ON(!cache); len = min(num, cache->key.offset - (bytenr - cache->key.objectid)); if (pin) { cache->pinned += len; cache->space_info->bytes_pinned += len; fs_info->total_pinned += len; } else { cache->pinned -= len; cache->space_info->bytes_pinned -= len; fs_info->total_pinned -= len; } next: bytenr += len; num -= len; } return 0; } int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct extent_io_tree *unpin) { u64 start; u64 end; int ret; struct extent_io_tree *free_space_cache; free_space_cache = &root->fs_info->free_space_cache; while(1) { ret = find_first_extent_bit(unpin, 0, &start, &end, EXTENT_DIRTY); if (ret) break; update_pinned_extents(root, start, end + 1 - start, 0); clear_extent_dirty(unpin, start, end, GFP_NOFS); set_extent_dirty(free_space_cache, start, end, GFP_NOFS); } return 0; } static int extent_root_pending_ops(struct btrfs_fs_info *info) { u64 start; u64 end; int ret; ret = find_first_extent_bit(&info->extent_ins, 0, &start, &end, EXTENT_LOCKED); if (!ret) { ret = find_first_extent_bit(&info->pending_del, 0, &start, &end, EXTENT_LOCKED); } return ret == 0; } static int finish_current_insert(struct btrfs_trans_handle *trans, struct btrfs_root *extent_root) { u64 start; u64 end; u64 priv; struct btrfs_fs_info *info = extent_root->fs_info; struct pending_extent_op *extent_op; struct btrfs_key key; int ret; int skinny_metadata = btrfs_fs_incompat(extent_root->fs_info, BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA); while(1) { ret = find_first_extent_bit(&info->extent_ins, 0, &start, &end, EXTENT_LOCKED); if (ret) break; ret = get_state_private(&info->extent_ins, start, &priv); BUG_ON(ret); extent_op = (struct pending_extent_op *)(unsigned long)priv; if (extent_op->type == PENDING_EXTENT_INSERT) { key.objectid = start; if (skinny_metadata) { key.offset = extent_op->level; key.type = BTRFS_METADATA_ITEM_KEY; } else { key.offset = extent_op->num_bytes; key.type = BTRFS_EXTENT_ITEM_KEY; } ret = alloc_reserved_tree_block(trans, extent_root, extent_root->root_key.objectid, trans->transid, extent_op->flags, &extent_op->key, extent_op->level, &key); BUG_ON(ret); } else { BUG_ON(1); } clear_extent_bits(&info->extent_ins, start, end, EXTENT_LOCKED, GFP_NOFS); kfree(extent_op); } return 0; } static int pin_down_bytes(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 bytenr, u64 num_bytes, int is_data) { int err = 0; struct extent_buffer *buf; if (is_data) goto pinit; buf = btrfs_find_tree_block(root, bytenr, num_bytes); if (!buf) goto pinit; /* we can reuse a block if it hasn't been written * and it is from this transaction. We can't * reuse anything from the tree log root because * it has tiny sub-transactions. */ if (btrfs_buffer_uptodate(buf, 0)) { u64 header_owner = btrfs_header_owner(buf); u64 header_transid = btrfs_header_generation(buf); if (header_owner != BTRFS_TREE_LOG_OBJECTID && header_transid == trans->transid && !btrfs_header_flag(buf, BTRFS_HEADER_FLAG_WRITTEN)) { clean_tree_block(NULL, root, buf); free_extent_buffer(buf); return 1; } } free_extent_buffer(buf); pinit: update_pinned_extents(root, bytenr, num_bytes, 1); BUG_ON(err < 0); return 0; } void btrfs_pin_extent(struct btrfs_fs_info *fs_info, u64 bytenr, u64 num_bytes) { update_pinned_extents(fs_info->extent_root, bytenr, num_bytes, 1); } void btrfs_unpin_extent(struct btrfs_fs_info *fs_info, u64 bytenr, u64 num_bytes) { update_pinned_extents(fs_info->extent_root, bytenr, num_bytes, 0); } /* * remove an extent from the root, returns 0 on success */ static int __free_extent(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 bytenr, u64 num_bytes, u64 parent, u64 root_objectid, u64 owner_objectid, u64 owner_offset, int refs_to_drop) { struct btrfs_key key; struct btrfs_path *path; struct btrfs_extent_ops *ops = root->fs_info->extent_ops; struct btrfs_root *extent_root = root->fs_info->extent_root; struct extent_buffer *leaf; struct btrfs_extent_item *ei; struct btrfs_extent_inline_ref *iref; int ret; int is_data; int extent_slot = 0; int found_extent = 0; int num_to_del = 1; u32 item_size; u64 refs; int skinny_metadata = btrfs_fs_incompat(extent_root->fs_info, BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA); if (root->fs_info->free_extent_hook) { root->fs_info->free_extent_hook(trans, root, bytenr, num_bytes, parent, root_objectid, owner_objectid, owner_offset, refs_to_drop); } path = btrfs_alloc_path(); if (!path) return -ENOMEM; path->reada = 1; is_data = owner_objectid >= BTRFS_FIRST_FREE_OBJECTID; if (is_data) skinny_metadata = 0; BUG_ON(!is_data && refs_to_drop != 1); ret = lookup_extent_backref(trans, extent_root, path, &iref, bytenr, num_bytes, parent, root_objectid, owner_objectid, owner_offset); if (ret == 0) { extent_slot = path->slots[0]; while (extent_slot >= 0) { btrfs_item_key_to_cpu(path->nodes[0], &key, extent_slot); if (key.objectid != bytenr) break; if (key.type == BTRFS_EXTENT_ITEM_KEY && key.offset == num_bytes) { found_extent = 1; break; } if (key.type == BTRFS_METADATA_ITEM_KEY && key.offset == owner_objectid) { found_extent = 1; break; } if (path->slots[0] - extent_slot > 5) break; extent_slot--; } #ifdef BTRFS_COMPAT_EXTENT_TREE_V0 item_size = btrfs_item_size_nr(path->nodes[0], extent_slot); if (found_extent && item_size < sizeof(*ei)) found_extent = 0; #endif if (!found_extent) { BUG_ON(iref); ret = remove_extent_backref(trans, extent_root, path, NULL, refs_to_drop, is_data); BUG_ON(ret); btrfs_release_path(path); key.objectid = bytenr; if (skinny_metadata) { key.type = BTRFS_METADATA_ITEM_KEY; key.offset = owner_objectid; } else { key.type = BTRFS_EXTENT_ITEM_KEY; key.offset = num_bytes; } ret = btrfs_search_slot(trans, extent_root, &key, path, -1, 1); if (ret > 0 && skinny_metadata && path->slots[0]) { path->slots[0]--; btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); if (key.objectid == bytenr && key.type == BTRFS_EXTENT_ITEM_KEY && key.offset == num_bytes) ret = 0; } if (ret > 0 && skinny_metadata) { skinny_metadata = 0; btrfs_release_path(path); key.type = BTRFS_EXTENT_ITEM_KEY; key.offset = num_bytes; ret = btrfs_search_slot(trans, extent_root, &key, path, -1, 1); } if (ret) { printk(KERN_ERR "umm, got %d back from search" ", was looking for %llu\n", ret, (unsigned long long)bytenr); btrfs_print_leaf(extent_root, path->nodes[0]); } BUG_ON(ret); extent_slot = path->slots[0]; } } else { printk(KERN_ERR "btrfs unable to find ref byte nr %llu " "parent %llu root %llu owner %llu offset %llu\n", (unsigned long long)bytenr, (unsigned long long)parent, (unsigned long long)root_objectid, (unsigned long long)owner_objectid, (unsigned long long)owner_offset); ret = -EIO; goto fail; } leaf = path->nodes[0]; item_size = btrfs_item_size_nr(leaf, extent_slot); #ifdef BTRFS_COMPAT_EXTENT_TREE_V0 if (item_size < sizeof(*ei)) { BUG_ON(found_extent || extent_slot != path->slots[0]); ret = convert_extent_item_v0(trans, extent_root, path, owner_objectid, 0); BUG_ON(ret < 0); btrfs_release_path(path); key.objectid = bytenr; key.type = BTRFS_EXTENT_ITEM_KEY; key.offset = num_bytes; ret = btrfs_search_slot(trans, extent_root, &key, path, -1, 1); if (ret) { printk(KERN_ERR "umm, got %d back from search" ", was looking for %llu\n", ret, (unsigned long long)bytenr); btrfs_print_leaf(extent_root, path->nodes[0]); } BUG_ON(ret); extent_slot = path->slots[0]; leaf = path->nodes[0]; item_size = btrfs_item_size_nr(leaf, extent_slot); } #endif BUG_ON(item_size < sizeof(*ei)); ei = btrfs_item_ptr(leaf, extent_slot, struct btrfs_extent_item); if (owner_objectid < BTRFS_FIRST_FREE_OBJECTID && key.type == BTRFS_EXTENT_ITEM_KEY) { struct btrfs_tree_block_info *bi; BUG_ON(item_size < sizeof(*ei) + sizeof(*bi)); bi = (struct btrfs_tree_block_info *)(ei + 1); WARN_ON(owner_objectid != btrfs_tree_block_level(leaf, bi)); } refs = btrfs_extent_refs(leaf, ei); BUG_ON(refs < refs_to_drop); refs -= refs_to_drop; if (refs > 0) { /* * In the case of inline back ref, reference count will * be updated by remove_extent_backref */ if (iref) { BUG_ON(!found_extent); } else { btrfs_set_extent_refs(leaf, ei, refs); btrfs_mark_buffer_dirty(leaf); } if (found_extent) { ret = remove_extent_backref(trans, extent_root, path, iref, refs_to_drop, is_data); BUG_ON(ret); } } else { int mark_free = 0; int pin = 1; if (found_extent) { BUG_ON(is_data && refs_to_drop != extent_data_ref_count(root, path, iref)); if (iref) { BUG_ON(path->slots[0] != extent_slot); } else { BUG_ON(path->slots[0] != extent_slot + 1); path->slots[0] = extent_slot; num_to_del = 2; } } if (ops && ops->free_extent) { ret = ops->free_extent(root, bytenr, num_bytes); if (ret > 0) { pin = 0; mark_free = 0; } } if (pin) { ret = pin_down_bytes(trans, root, bytenr, num_bytes, is_data); if (ret > 0) mark_free = 1; BUG_ON(ret < 0); } ret = btrfs_del_items(trans, extent_root, path, path->slots[0], num_to_del); BUG_ON(ret); btrfs_release_path(path); if (is_data) { ret = btrfs_del_csums(trans, root, bytenr, num_bytes); BUG_ON(ret); } update_block_group(trans, root, bytenr, num_bytes, 0, mark_free); } fail: btrfs_free_path(path); finish_current_insert(trans, extent_root); return ret; } /* * find all the blocks marked as pending in the radix tree and remove * them from the extent map */ static int del_pending_extents(struct btrfs_trans_handle *trans, struct btrfs_root *extent_root) { int ret; int err = 0; u64 start; u64 end; u64 priv; struct extent_io_tree *pending_del; struct extent_io_tree *extent_ins; struct pending_extent_op *extent_op; extent_ins = &extent_root->fs_info->extent_ins; pending_del = &extent_root->fs_info->pending_del; while(1) { ret = find_first_extent_bit(pending_del, 0, &start, &end, EXTENT_LOCKED); if (ret) break; ret = get_state_private(pending_del, start, &priv); BUG_ON(ret); extent_op = (struct pending_extent_op *)(unsigned long)priv; clear_extent_bits(pending_del, start, end, EXTENT_LOCKED, GFP_NOFS); if (!test_range_bit(extent_ins, start, end, EXTENT_LOCKED, 0)) { ret = __free_extent(trans, extent_root, start, end + 1 - start, 0, extent_root->root_key.objectid, extent_op->level, 0, 1); kfree(extent_op); } else { kfree(extent_op); ret = get_state_private(extent_ins, start, &priv); BUG_ON(ret); extent_op = (struct pending_extent_op *) (unsigned long)priv; clear_extent_bits(extent_ins, start, end, EXTENT_LOCKED, GFP_NOFS); if (extent_op->type == PENDING_BACKREF_UPDATE) BUG_ON(1); kfree(extent_op); } if (ret) err = ret; } return err; } /* * remove an extent from the root, returns 0 on success */ int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 bytenr, u64 num_bytes, u64 parent, u64 root_objectid, u64 owner, u64 offset) { struct btrfs_root *extent_root = root->fs_info->extent_root; int pending_ret; int ret; WARN_ON(num_bytes < root->sectorsize); if (root == extent_root) { struct pending_extent_op *extent_op; extent_op = kmalloc(sizeof(*extent_op), GFP_NOFS); BUG_ON(!extent_op); extent_op->type = PENDING_EXTENT_DELETE; extent_op->bytenr = bytenr; extent_op->num_bytes = num_bytes; extent_op->level = (int)owner; set_extent_bits(&root->fs_info->pending_del, bytenr, bytenr + num_bytes - 1, EXTENT_LOCKED, GFP_NOFS); set_state_private(&root->fs_info->pending_del, bytenr, (unsigned long)extent_op); return 0; } ret = __free_extent(trans, root, bytenr, num_bytes, parent, root_objectid, owner, offset, 1); pending_ret = del_pending_extents(trans, root->fs_info->extent_root); return ret ? ret : pending_ret; } static u64 stripe_align(struct btrfs_root *root, u64 val) { u64 mask = ((u64)root->stripesize - 1); u64 ret = (val + mask) & ~mask; return ret; } /* * walks the btree of allocated extents and find a hole of a given size. * The key ins is changed to record the hole: * ins->objectid == block start * ins->flags = BTRFS_EXTENT_ITEM_KEY * ins->offset == number of blocks * Any available blocks before search_start are skipped. */ static int noinline find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root *orig_root, u64 num_bytes, u64 empty_size, u64 search_start, u64 search_end, u64 hint_byte, struct btrfs_key *ins, u64 exclude_start, u64 exclude_nr, int data) { int ret; u64 orig_search_start = search_start; struct btrfs_root * root = orig_root->fs_info->extent_root; struct btrfs_fs_info *info = root->fs_info; u64 total_needed = num_bytes; struct btrfs_block_group_cache *block_group; int full_scan = 0; int wrapped = 0; WARN_ON(num_bytes < root->sectorsize); btrfs_set_key_type(ins, BTRFS_EXTENT_ITEM_KEY); search_start = stripe_align(root, search_start); if (hint_byte) { block_group = btrfs_lookup_first_block_group(info, hint_byte); if (!block_group) hint_byte = search_start; block_group = btrfs_find_block_group(root, block_group, hint_byte, data, 1); } else { block_group = btrfs_find_block_group(root, trans->block_group, search_start, data, 1); } total_needed += empty_size; check_failed: search_start = stripe_align(root, search_start); if (!block_group) { block_group = btrfs_lookup_first_block_group(info, search_start); if (!block_group) block_group = btrfs_lookup_first_block_group(info, orig_search_start); } ret = find_search_start(root, &block_group, &search_start, total_needed, data); if (ret) goto new_group; ins->objectid = search_start; ins->offset = num_bytes; if (ins->objectid + num_bytes > block_group->key.objectid + block_group->key.offset) { search_start = block_group->key.objectid + block_group->key.offset; goto new_group; } if (test_range_bit(&info->extent_ins, ins->objectid, ins->objectid + num_bytes -1, EXTENT_LOCKED, 0)) { search_start = ins->objectid + num_bytes; goto new_group; } if (test_range_bit(&info->pinned_extents, ins->objectid, ins->objectid + num_bytes -1, EXTENT_DIRTY, 0)) { search_start = ins->objectid + num_bytes; goto new_group; } if (exclude_nr > 0 && (ins->objectid + num_bytes > exclude_start && ins->objectid < exclude_start + exclude_nr)) { search_start = exclude_start + exclude_nr; goto new_group; } if (!(data & BTRFS_BLOCK_GROUP_DATA)) { block_group = btrfs_lookup_block_group(info, ins->objectid); if (block_group) trans->block_group = block_group; } ins->offset = num_bytes; return 0; new_group: block_group = btrfs_lookup_first_block_group(info, search_start); if (!block_group) { search_start = orig_search_start; if (full_scan) { ret = -ENOSPC; goto error; } if (wrapped) { if (!full_scan) total_needed -= empty_size; full_scan = 1; } else wrapped = 1; } cond_resched(); block_group = btrfs_find_block_group(root, block_group, search_start, data, 0); goto check_failed; error: return ret; } int btrfs_reserve_extent(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 num_bytes, u64 empty_size, u64 hint_byte, u64 search_end, struct btrfs_key *ins, int data) { int ret; u64 search_start = 0; u64 alloc_profile; struct btrfs_fs_info *info = root->fs_info; if (info->extent_ops) { struct btrfs_extent_ops *ops = info->extent_ops; ret = ops->alloc_extent(root, num_bytes, hint_byte, ins); BUG_ON(ret); goto found; } if (data) { alloc_profile = info->avail_data_alloc_bits & info->data_alloc_profile; data = BTRFS_BLOCK_GROUP_DATA | alloc_profile; } else if ((info->system_allocs > 0 || root == info->chunk_root) && info->system_allocs >= 0) { alloc_profile = info->avail_system_alloc_bits & info->system_alloc_profile; data = BTRFS_BLOCK_GROUP_SYSTEM | alloc_profile; } else { alloc_profile = info->avail_metadata_alloc_bits & info->metadata_alloc_profile; data = BTRFS_BLOCK_GROUP_METADATA | alloc_profile; } if (root->ref_cows) { if (!(data & BTRFS_BLOCK_GROUP_METADATA)) { ret = do_chunk_alloc(trans, root->fs_info->extent_root, num_bytes, BTRFS_BLOCK_GROUP_METADATA); BUG_ON(ret); } ret = do_chunk_alloc(trans, root->fs_info->extent_root, num_bytes + 2 * 1024 * 1024, data); BUG_ON(ret); } WARN_ON(num_bytes < root->sectorsize); ret = find_free_extent(trans, root, num_bytes, empty_size, search_start, search_end, hint_byte, ins, trans->alloc_exclude_start, trans->alloc_exclude_nr, data); BUG_ON(ret); found: clear_extent_dirty(&root->fs_info->free_space_cache, ins->objectid, ins->objectid + ins->offset - 1, GFP_NOFS); return ret; } static int alloc_reserved_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 root_objectid, u64 generation, u64 flags, struct btrfs_disk_key *key, int level, struct btrfs_key *ins) { int ret; struct btrfs_fs_info *fs_info = root->fs_info; struct btrfs_extent_item *extent_item; struct btrfs_tree_block_info *block_info; struct btrfs_extent_inline_ref *iref; struct btrfs_path *path; struct extent_buffer *leaf; u32 size = sizeof(*extent_item) + sizeof(*iref); int skinny_metadata = btrfs_fs_incompat(fs_info, BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA); if (!skinny_metadata) size += sizeof(*block_info); path = btrfs_alloc_path(); BUG_ON(!path); ret = btrfs_insert_empty_item(trans, fs_info->extent_root, path, ins, size); BUG_ON(ret); leaf = path->nodes[0]; extent_item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_item); btrfs_set_extent_refs(leaf, extent_item, 1); btrfs_set_extent_generation(leaf, extent_item, generation); btrfs_set_extent_flags(leaf, extent_item, flags | BTRFS_EXTENT_FLAG_TREE_BLOCK); if (skinny_metadata) { iref = (struct btrfs_extent_inline_ref *)(extent_item + 1); } else { block_info = (struct btrfs_tree_block_info *)(extent_item + 1); btrfs_set_tree_block_key(leaf, block_info, key); btrfs_set_tree_block_level(leaf, block_info, level); iref = (struct btrfs_extent_inline_ref *)(block_info + 1); } btrfs_set_extent_inline_ref_type(leaf, iref, BTRFS_TREE_BLOCK_REF_KEY); btrfs_set_extent_inline_ref_offset(leaf, iref, root_objectid); btrfs_mark_buffer_dirty(leaf); btrfs_free_path(path); ret = update_block_group(trans, root, ins->objectid, root->leafsize, 1, 0); return ret; } static int alloc_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 num_bytes, u64 root_objectid, u64 generation, u64 flags, struct btrfs_disk_key *key, int level, u64 empty_size, u64 hint_byte, u64 search_end, struct btrfs_key *ins) { int ret; ret = btrfs_reserve_extent(trans, root, num_bytes, empty_size, hint_byte, search_end, ins, 0); BUG_ON(ret); if (root_objectid == BTRFS_EXTENT_TREE_OBJECTID) { struct pending_extent_op *extent_op; extent_op = kmalloc(sizeof(*extent_op), GFP_NOFS); BUG_ON(!extent_op); extent_op->type = PENDING_EXTENT_INSERT; extent_op->bytenr = ins->objectid; extent_op->num_bytes = ins->offset; extent_op->level = level; extent_op->flags = flags; memcpy(&extent_op->key, key, sizeof(*key)); set_extent_bits(&root->fs_info->extent_ins, ins->objectid, ins->objectid + ins->offset - 1, EXTENT_LOCKED, GFP_NOFS); set_state_private(&root->fs_info->extent_ins, ins->objectid, (unsigned long)extent_op); } else { if (btrfs_fs_incompat(root->fs_info, BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA)) { ins->offset = level; ins->type = BTRFS_METADATA_ITEM_KEY; } ret = alloc_reserved_tree_block(trans, root, root_objectid, generation, flags, key, level, ins); finish_current_insert(trans, root->fs_info->extent_root); del_pending_extents(trans, root->fs_info->extent_root); } return ret; } /* * helper function to allocate a block for a given tree * returns the tree buffer or NULL. */ struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, u32 blocksize, u64 root_objectid, struct btrfs_disk_key *key, int level, u64 hint, u64 empty_size) { struct btrfs_key ins; int ret; struct extent_buffer *buf; ret = alloc_tree_block(trans, root, blocksize, root_objectid, trans->transid, 0, key, level, empty_size, hint, (u64)-1, &ins); if (ret) { BUG_ON(ret > 0); return ERR_PTR(ret); } buf = btrfs_find_create_tree_block(root, ins.objectid, blocksize); if (!buf) { btrfs_free_extent(trans, root, ins.objectid, ins.offset, 0, root->root_key.objectid, level, 0); BUG_ON(1); return ERR_PTR(-ENOMEM); } btrfs_set_buffer_uptodate(buf); trans->blocks_used++; return buf; } #if 0 static int noinline drop_leaf_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct extent_buffer *leaf) { u64 leaf_owner; u64 leaf_generation; struct btrfs_key key; struct btrfs_file_extent_item *fi; int i; int nritems; int ret; BUG_ON(!btrfs_is_leaf(leaf)); nritems = btrfs_header_nritems(leaf); leaf_owner = btrfs_header_owner(leaf); leaf_generation = btrfs_header_generation(leaf); for (i = 0; i < nritems; i++) { u64 disk_bytenr; btrfs_item_key_to_cpu(leaf, &key, i); if (btrfs_key_type(&key) != BTRFS_EXTENT_DATA_KEY) continue; fi = btrfs_item_ptr(leaf, i, struct btrfs_file_extent_item); if (btrfs_file_extent_type(leaf, fi) == BTRFS_FILE_EXTENT_INLINE) continue; /* * FIXME make sure to insert a trans record that * repeats the snapshot del on crash */ disk_bytenr = btrfs_file_extent_disk_bytenr(leaf, fi); if (disk_bytenr == 0) continue; ret = btrfs_free_extent(trans, root, disk_bytenr, btrfs_file_extent_disk_num_bytes(leaf, fi), leaf->start, leaf_owner, leaf_generation, key.objectid, 0); BUG_ON(ret); } return 0; } static void noinline reada_walk_down(struct btrfs_root *root, struct extent_buffer *node, int slot) { u64 bytenr; u64 last = 0; u32 nritems; u32 refs; u32 blocksize; int ret; int i; int level; int skipped = 0; nritems = btrfs_header_nritems(node); level = btrfs_header_level(node); if (level) return; for (i = slot; i < nritems && skipped < 32; i++) { bytenr = btrfs_node_blockptr(node, i); if (last && ((bytenr > last && bytenr - last > 32 * 1024) || (last > bytenr && last - bytenr > 32 * 1024))) { skipped++; continue; } blocksize = btrfs_level_size(root, level - 1); if (i != slot) { ret = btrfs_lookup_extent_ref(NULL, root, bytenr, blocksize, &refs); BUG_ON(ret); if (refs != 1) { skipped++; continue; } } mutex_unlock(&root->fs_info->fs_mutex); ret = readahead_tree_block(root, bytenr, blocksize, btrfs_node_ptr_generation(node, i)); last = bytenr + blocksize; cond_resched(); mutex_lock(&root->fs_info->fs_mutex); if (ret) break; } } /* * helper function for drop_snapshot, this walks down the tree dropping ref * counts as it goes. */ static int noinline walk_down_tree(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, int *level) { u64 root_owner; u64 root_gen; u64 bytenr; u64 ptr_gen; struct extent_buffer *next; struct extent_buffer *cur; struct extent_buffer *parent; u32 blocksize; int ret; u32 refs; WARN_ON(*level < 0); WARN_ON(*level >= BTRFS_MAX_LEVEL); ret = btrfs_lookup_extent_ref(trans, root, path->nodes[*level]->start, path->nodes[*level]->len, &refs); BUG_ON(ret); if (refs > 1) goto out; /* * walk down to the last node level and free all the leaves */ while(*level >= 0) { WARN_ON(*level < 0); WARN_ON(*level >= BTRFS_MAX_LEVEL); cur = path->nodes[*level]; if (btrfs_header_level(cur) != *level) WARN_ON(1); if (path->slots[*level] >= btrfs_header_nritems(cur)) break; if (*level == 0) { ret = drop_leaf_ref(trans, root, cur); BUG_ON(ret); break; } bytenr = btrfs_node_blockptr(cur, path->slots[*level]); ptr_gen = btrfs_node_ptr_generation(cur, path->slots[*level]); blocksize = btrfs_level_size(root, *level - 1); ret = btrfs_lookup_extent_ref(trans, root, bytenr, blocksize, &refs); BUG_ON(ret); if (refs != 1) { parent = path->nodes[*level]; root_owner = btrfs_header_owner(parent); root_gen = btrfs_header_generation(parent); path->slots[*level]++; ret = btrfs_free_extent(trans, root, bytenr, blocksize, parent->start, root_owner, root_gen, *level - 1, 1); BUG_ON(ret); continue; } next = btrfs_find_tree_block(root, bytenr, blocksize); if (!next || !btrfs_buffer_uptodate(next, ptr_gen)) { free_extent_buffer(next); reada_walk_down(root, cur, path->slots[*level]); mutex_unlock(&root->fs_info->fs_mutex); next = read_tree_block(root, bytenr, blocksize, ptr_gen); mutex_lock(&root->fs_info->fs_mutex); } WARN_ON(*level <= 0); if (path->nodes[*level-1]) free_extent_buffer(path->nodes[*level-1]); path->nodes[*level-1] = next; *level = btrfs_header_level(next); path->slots[*level] = 0; } out: WARN_ON(*level < 0); WARN_ON(*level >= BTRFS_MAX_LEVEL); if (path->nodes[*level] == root->node) { root_owner = root->root_key.objectid; parent = path->nodes[*level]; } else { parent = path->nodes[*level + 1]; root_owner = btrfs_header_owner(parent); } root_gen = btrfs_header_generation(parent); ret = btrfs_free_extent(trans, root, path->nodes[*level]->start, path->nodes[*level]->len, parent->start, root_owner, root_gen, *level, 1); free_extent_buffer(path->nodes[*level]); path->nodes[*level] = NULL; *level += 1; BUG_ON(ret); return 0; } /* * helper for dropping snapshots. This walks back up the tree in the path * to find the first node higher up where we haven't yet gone through * all the slots */ static int noinline walk_up_tree(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, int *level) { u64 root_owner; u64 root_gen; struct btrfs_root_item *root_item = &root->root_item; int i; int slot; int ret; for(i = *level; i < BTRFS_MAX_LEVEL - 1 && path->nodes[i]; i++) { slot = path->slots[i]; if (slot < btrfs_header_nritems(path->nodes[i]) - 1) { struct extent_buffer *node; struct btrfs_disk_key disk_key; node = path->nodes[i]; path->slots[i]++; *level = i; WARN_ON(*level == 0); btrfs_node_key(node, &disk_key, path->slots[i]); memcpy(&root_item->drop_progress, &disk_key, sizeof(disk_key)); root_item->drop_level = i; return 0; } else { struct extent_buffer *parent; if (path->nodes[*level] == root->node) parent = path->nodes[*level]; else parent = path->nodes[*level + 1]; root_owner = btrfs_header_owner(parent); root_gen = btrfs_header_generation(parent); ret = btrfs_free_extent(trans, root, path->nodes[*level]->start, path->nodes[*level]->len, parent->start, root_owner, root_gen, *level, 1); BUG_ON(ret); free_extent_buffer(path->nodes[*level]); path->nodes[*level] = NULL; *level = i + 1; } } return 1; } #endif int btrfs_free_block_groups(struct btrfs_fs_info *info) { struct btrfs_space_info *sinfo; struct btrfs_block_group_cache *cache; u64 start; u64 end; u64 ptr; int ret; while(1) { ret = find_first_extent_bit(&info->block_group_cache, 0, &start, &end, (unsigned int)-1); if (ret) break; ret = get_state_private(&info->block_group_cache, start, &ptr); if (!ret) { cache = u64_to_ptr(ptr); if (cache->free_space_ctl) { btrfs_remove_free_space_cache(cache); kfree(cache->free_space_ctl); } kfree(cache); } clear_extent_bits(&info->block_group_cache, start, end, (unsigned int)-1, GFP_NOFS); } while(1) { ret = find_first_extent_bit(&info->free_space_cache, 0, &start, &end, EXTENT_DIRTY); if (ret) break; clear_extent_dirty(&info->free_space_cache, start, end, GFP_NOFS); } while (!list_empty(&info->space_info)) { sinfo = list_entry(info->space_info.next, struct btrfs_space_info, list); list_del_init(&sinfo->list); kfree(sinfo); } return 0; } static int find_first_block_group(struct btrfs_root *root, struct btrfs_path *path, struct btrfs_key *key) { int ret; struct btrfs_key found_key; struct extent_buffer *leaf; int slot; ret = btrfs_search_slot(NULL, root, key, path, 0, 0); if (ret < 0) return ret; while(1) { slot = path->slots[0]; leaf = path->nodes[0]; if (slot >= btrfs_header_nritems(leaf)) { ret = btrfs_next_leaf(root, path); if (ret == 0) continue; if (ret < 0) goto error; break; } btrfs_item_key_to_cpu(leaf, &found_key, slot); if (found_key.objectid >= key->objectid && found_key.type == BTRFS_BLOCK_GROUP_ITEM_KEY) return 0; path->slots[0]++; } ret = -ENOENT; error: return ret; } int btrfs_read_block_groups(struct btrfs_root *root) { struct btrfs_path *path; int ret; int bit; struct btrfs_block_group_cache *cache; struct btrfs_fs_info *info = root->fs_info; struct btrfs_space_info *space_info; struct extent_io_tree *block_group_cache; struct btrfs_key key; struct btrfs_key found_key; struct extent_buffer *leaf; block_group_cache = &info->block_group_cache; root = info->extent_root; key.objectid = 0; key.offset = 0; btrfs_set_key_type(&key, BTRFS_BLOCK_GROUP_ITEM_KEY); path = btrfs_alloc_path(); if (!path) return -ENOMEM; while(1) { ret = find_first_block_group(root, path, &key); if (ret > 0) { ret = 0; goto error; } if (ret != 0) { goto error; } leaf = path->nodes[0]; btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); cache = kzalloc(sizeof(*cache), GFP_NOFS); if (!cache) { ret = -ENOMEM; break; } read_extent_buffer(leaf, &cache->item, btrfs_item_ptr_offset(leaf, path->slots[0]), sizeof(cache->item)); memcpy(&cache->key, &found_key, sizeof(found_key)); cache->cached = 0; cache->pinned = 0; key.objectid = found_key.objectid + found_key.offset; btrfs_release_path(path); cache->flags = btrfs_block_group_flags(&cache->item); bit = 0; if (cache->flags & BTRFS_BLOCK_GROUP_DATA) { bit = BLOCK_GROUP_DATA; } else if (cache->flags & BTRFS_BLOCK_GROUP_SYSTEM) { bit = BLOCK_GROUP_SYSTEM; } else if (cache->flags & BTRFS_BLOCK_GROUP_METADATA) { bit = BLOCK_GROUP_METADATA; } set_avail_alloc_bits(info, cache->flags); if (btrfs_chunk_readonly(root, cache->key.objectid)) cache->ro = 1; ret = update_space_info(info, cache->flags, found_key.offset, btrfs_block_group_used(&cache->item), &space_info); BUG_ON(ret); cache->space_info = space_info; /* use EXTENT_LOCKED to prevent merging */ set_extent_bits(block_group_cache, found_key.objectid, found_key.objectid + found_key.offset - 1, bit | EXTENT_LOCKED, GFP_NOFS); set_state_private(block_group_cache, found_key.objectid, (unsigned long)cache); } ret = 0; error: btrfs_free_path(path); return ret; } struct btrfs_block_group_cache * btrfs_add_block_group(struct btrfs_fs_info *fs_info, u64 bytes_used, u64 type, u64 chunk_objectid, u64 chunk_offset, u64 size) { int ret; int bit = 0; struct btrfs_block_group_cache *cache; struct extent_io_tree *block_group_cache; block_group_cache = &fs_info->block_group_cache; cache = kzalloc(sizeof(*cache), GFP_NOFS); BUG_ON(!cache); cache->key.objectid = chunk_offset; cache->key.offset = size; btrfs_set_key_type(&cache->key, BTRFS_BLOCK_GROUP_ITEM_KEY); btrfs_set_block_group_used(&cache->item, bytes_used); btrfs_set_block_group_chunk_objectid(&cache->item, chunk_objectid); cache->flags = type; btrfs_set_block_group_flags(&cache->item, type); ret = update_space_info(fs_info, cache->flags, size, bytes_used, &cache->space_info); BUG_ON(ret); bit = block_group_state_bits(type); ret = set_extent_bits(block_group_cache, chunk_offset, chunk_offset + size - 1, bit | EXTENT_LOCKED, GFP_NOFS); BUG_ON(ret); ret = set_state_private(block_group_cache, chunk_offset, (unsigned long)cache); BUG_ON(ret); set_avail_alloc_bits(fs_info, type); return cache; } int btrfs_make_block_group(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 bytes_used, u64 type, u64 chunk_objectid, u64 chunk_offset, u64 size) { int ret; struct btrfs_root *extent_root; struct btrfs_block_group_cache *cache; cache = btrfs_add_block_group(root->fs_info, bytes_used, type, chunk_objectid, chunk_offset, size); extent_root = root->fs_info->extent_root; ret = btrfs_insert_item(trans, extent_root, &cache->key, &cache->item, sizeof(cache->item)); BUG_ON(ret); ret = finish_current_insert(trans, extent_root); BUG_ON(ret); ret = del_pending_extents(trans, extent_root); BUG_ON(ret); return 0; } /* * This is for converter use only. * * In that case, we don't know where are free blocks located. * Therefore all block group cache entries must be setup properly * before doing any block allocation. */ int btrfs_make_block_groups(struct btrfs_trans_handle *trans, struct btrfs_root *root) { u64 total_bytes; u64 cur_start; u64 group_type; u64 group_size; u64 group_align; u64 total_data = 0; u64 total_metadata = 0; u64 chunk_objectid; int ret; int bit; struct btrfs_root *extent_root; struct btrfs_block_group_cache *cache; struct extent_io_tree *block_group_cache; extent_root = root->fs_info->extent_root; block_group_cache = &root->fs_info->block_group_cache; chunk_objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID; total_bytes = btrfs_super_total_bytes(root->fs_info->super_copy); group_align = 64 * root->sectorsize; cur_start = 0; while (cur_start < total_bytes) { group_size = total_bytes / 12; group_size = min_t(u64, group_size, total_bytes - cur_start); if (cur_start == 0) { bit = BLOCK_GROUP_SYSTEM; group_type = BTRFS_BLOCK_GROUP_SYSTEM; group_size /= 4; group_size &= ~(group_align - 1); group_size = max_t(u64, group_size, 8 * 1024 * 1024); group_size = min_t(u64, group_size, 32 * 1024 * 1024); } else { group_size &= ~(group_align - 1); if (total_data >= total_metadata * 2) { group_type = BTRFS_BLOCK_GROUP_METADATA; group_size = min_t(u64, group_size, 1ULL * 1024 * 1024 * 1024); total_metadata += group_size; } else { group_type = BTRFS_BLOCK_GROUP_DATA; group_size = min_t(u64, group_size, 5ULL * 1024 * 1024 * 1024); total_data += group_size; } if ((total_bytes - cur_start) * 4 < group_size * 5) group_size = total_bytes - cur_start; } cache = kzalloc(sizeof(*cache), GFP_NOFS); BUG_ON(!cache); cache->key.objectid = cur_start; cache->key.offset = group_size; btrfs_set_key_type(&cache->key, BTRFS_BLOCK_GROUP_ITEM_KEY); btrfs_set_block_group_used(&cache->item, 0); btrfs_set_block_group_chunk_objectid(&cache->item, chunk_objectid); btrfs_set_block_group_flags(&cache->item, group_type); cache->flags = group_type; ret = update_space_info(root->fs_info, group_type, group_size, 0, &cache->space_info); BUG_ON(ret); set_avail_alloc_bits(extent_root->fs_info, group_type); set_extent_bits(block_group_cache, cur_start, cur_start + group_size - 1, bit | EXTENT_LOCKED, GFP_NOFS); set_state_private(block_group_cache, cur_start, (unsigned long)cache); cur_start += group_size; } /* then insert all the items */ cur_start = 0; while(cur_start < total_bytes) { cache = btrfs_lookup_block_group(root->fs_info, cur_start); BUG_ON(!cache); ret = btrfs_insert_item(trans, extent_root, &cache->key, &cache->item, sizeof(cache->item)); BUG_ON(ret); finish_current_insert(trans, extent_root); ret = del_pending_extents(trans, extent_root); BUG_ON(ret); cur_start = cache->key.objectid + cache->key.offset; } return 0; } int btrfs_update_block_group(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 bytenr, u64 num_bytes, int alloc, int mark_free) { return update_block_group(trans, root, bytenr, num_bytes, alloc, mark_free); } /* * Fixup block accounting. The initial block accounting created by * make_block_groups isn't accuracy in this case. */ int btrfs_fix_block_accounting(struct btrfs_trans_handle *trans, struct btrfs_root *root) { int ret; int slot; u64 start = 0; u64 bytes_used = 0; struct btrfs_path path; struct btrfs_key key; struct extent_buffer *leaf; struct btrfs_block_group_cache *cache; struct btrfs_fs_info *fs_info = root->fs_info; root = root->fs_info->extent_root; while(extent_root_pending_ops(fs_info)) { ret = finish_current_insert(trans, root); if (ret) return ret; ret = del_pending_extents(trans, root); if (ret) return ret; } while(1) { cache = btrfs_lookup_first_block_group(fs_info, start); if (!cache) break; start = cache->key.objectid + cache->key.offset; btrfs_set_block_group_used(&cache->item, 0); cache->space_info->bytes_used = 0; set_extent_bits(&root->fs_info->block_group_cache, cache->key.objectid, cache->key.objectid + cache->key.offset -1, BLOCK_GROUP_DIRTY, GFP_NOFS); } btrfs_init_path(&path); key.offset = 0; key.objectid = 0; btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY); ret = btrfs_search_slot(trans, root->fs_info->extent_root, &key, &path, 0, 0); if (ret < 0) return ret; while(1) { leaf = path.nodes[0]; slot = path.slots[0]; if (slot >= btrfs_header_nritems(leaf)) { ret = btrfs_next_leaf(root, &path); if (ret < 0) return ret; if (ret > 0) break; leaf = path.nodes[0]; slot = path.slots[0]; } btrfs_item_key_to_cpu(leaf, &key, slot); if (key.type == BTRFS_EXTENT_ITEM_KEY) { bytes_used += key.offset; ret = btrfs_update_block_group(trans, root, key.objectid, key.offset, 1, 0); BUG_ON(ret); } else if (key.type == BTRFS_METADATA_ITEM_KEY) { bytes_used += root->leafsize; ret = btrfs_update_block_group(trans, root, key.objectid, root->leafsize, 1, 0); BUG_ON(ret); } path.slots[0]++; } btrfs_set_super_bytes_used(root->fs_info->super_copy, bytes_used); btrfs_release_path(&path); return 0; } /* * Record a file extent. Do all the required works, such as inserting * file extent item, inserting extent item and backref item into extent * tree and updating block accounting. */ int btrfs_record_file_extent(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 objectid, struct btrfs_inode_item *inode, u64 file_pos, u64 disk_bytenr, u64 num_bytes) { int ret; struct btrfs_fs_info *info = root->fs_info; struct btrfs_root *extent_root = info->extent_root; struct extent_buffer *leaf; struct btrfs_file_extent_item *fi; struct btrfs_key ins_key; struct btrfs_path path; struct btrfs_extent_item *ei; u64 nbytes; if (disk_bytenr == 0) { ret = btrfs_insert_file_extent(trans, root, objectid, file_pos, disk_bytenr, num_bytes, num_bytes); return ret; } btrfs_init_path(&path); ins_key.objectid = objectid; ins_key.offset = file_pos; btrfs_set_key_type(&ins_key, BTRFS_EXTENT_DATA_KEY); ret = btrfs_insert_empty_item(trans, root, &path, &ins_key, sizeof(*fi)); if (ret) goto fail; leaf = path.nodes[0]; fi = btrfs_item_ptr(leaf, path.slots[0], struct btrfs_file_extent_item); btrfs_set_file_extent_generation(leaf, fi, trans->transid); btrfs_set_file_extent_type(leaf, fi, BTRFS_FILE_EXTENT_REG); btrfs_set_file_extent_disk_bytenr(leaf, fi, disk_bytenr); btrfs_set_file_extent_disk_num_bytes(leaf, fi, num_bytes); btrfs_set_file_extent_offset(leaf, fi, 0); btrfs_set_file_extent_num_bytes(leaf, fi, num_bytes); btrfs_set_file_extent_ram_bytes(leaf, fi, num_bytes); btrfs_set_file_extent_compression(leaf, fi, 0); btrfs_set_file_extent_encryption(leaf, fi, 0); btrfs_set_file_extent_other_encoding(leaf, fi, 0); btrfs_mark_buffer_dirty(leaf); nbytes = btrfs_stack_inode_nbytes(inode) + num_bytes; btrfs_set_stack_inode_nbytes(inode, nbytes); btrfs_release_path(&path); ins_key.objectid = disk_bytenr; ins_key.offset = num_bytes; ins_key.type = BTRFS_EXTENT_ITEM_KEY; ret = btrfs_insert_empty_item(trans, extent_root, &path, &ins_key, sizeof(*ei)); if (ret == 0) { leaf = path.nodes[0]; ei = btrfs_item_ptr(leaf, path.slots[0], struct btrfs_extent_item); btrfs_set_extent_refs(leaf, ei, 0); btrfs_set_extent_generation(leaf, ei, 0); btrfs_set_extent_flags(leaf, ei, BTRFS_EXTENT_FLAG_DATA); btrfs_mark_buffer_dirty(leaf); ret = btrfs_update_block_group(trans, root, disk_bytenr, num_bytes, 1, 0); if (ret) goto fail; } else if (ret != -EEXIST) { goto fail; } btrfs_extent_post_op(trans, extent_root); ret = btrfs_inc_extent_ref(trans, root, disk_bytenr, num_bytes, 0, root->root_key.objectid, objectid, file_pos); if (ret) goto fail; ret = 0; fail: btrfs_release_path(&path); return ret; } partclone-0.2.86/src/btrfs/extent_io.c000066400000000000000000000504761262102574200176640ustar00rootroot00000000000000 /* * Copyright (C) 2007 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. */ #define _XOPEN_SOURCE 600 #define __USE_XOPEN2K #include #include #include #include #include #include #include "kerncompat.h" #include "extent_io.h" #include "list.h" #include "ctree.h" #include "volumes.h" void extent_io_tree_init(struct extent_io_tree *tree) { cache_tree_init(&tree->state); cache_tree_init(&tree->cache); INIT_LIST_HEAD(&tree->lru); tree->cache_size = 0; } static struct extent_state *alloc_extent_state(void) { struct extent_state *state; state = malloc(sizeof(*state)); if (!state) return NULL; state->cache_node.objectid = 0; state->refs = 1; state->state = 0; state->xprivate = 0; return state; } static void btrfs_free_extent_state(struct extent_state *state) { state->refs--; BUG_ON(state->refs < 0); if (state->refs == 0) free(state); } static void free_extent_state_func(struct cache_extent *cache) { struct extent_state *es; es = container_of(cache, struct extent_state, cache_node); btrfs_free_extent_state(es); } void extent_io_tree_cleanup(struct extent_io_tree *tree) { struct extent_buffer *eb; while(!list_empty(&tree->lru)) { eb = list_entry(tree->lru.next, struct extent_buffer, lru); fprintf(stderr, "extent buffer leak: " "start %llu len %u\n", (unsigned long long)eb->start, eb->len); free_extent_buffer(eb); } cache_tree_free_extents(&tree->state, free_extent_state_func); } static inline void update_extent_state(struct extent_state *state) { state->cache_node.start = state->start; state->cache_node.size = state->end + 1 - state->start; } /* * Utility function to look for merge candidates inside a given range. * Any extents with matching state are merged together into a single * extent in the tree. Extents with EXTENT_IO in their state field are * not merged */ static int merge_state(struct extent_io_tree *tree, struct extent_state *state) { struct extent_state *other; struct cache_extent *other_node; if (state->state & EXTENT_IOBITS) return 0; other_node = prev_cache_extent(&state->cache_node); if (other_node) { other = container_of(other_node, struct extent_state, cache_node); if (other->end == state->start - 1 && other->state == state->state) { state->start = other->start; update_extent_state(state); remove_cache_extent(&tree->state, &other->cache_node); btrfs_free_extent_state(other); } } other_node = next_cache_extent(&state->cache_node); if (other_node) { other = container_of(other_node, struct extent_state, cache_node); if (other->start == state->end + 1 && other->state == state->state) { other->start = state->start; update_extent_state(other); remove_cache_extent(&tree->state, &state->cache_node); btrfs_free_extent_state(state); } } return 0; } /* * insert an extent_state struct into the tree. 'bits' are set on the * struct before it is inserted. */ static int insert_state(struct extent_io_tree *tree, struct extent_state *state, u64 start, u64 end, int bits) { int ret; BUG_ON(end < start); state->state |= bits; state->start = start; state->end = end; update_extent_state(state); ret = insert_cache_extent(&tree->state, &state->cache_node); BUG_ON(ret); merge_state(tree, state); return 0; } /* * split a given extent state struct in two, inserting the preallocated * struct 'prealloc' as the newly created second half. 'split' indicates an * offset inside 'orig' where it should be split. */ static int split_state(struct extent_io_tree *tree, struct extent_state *orig, struct extent_state *prealloc, u64 split) { int ret; prealloc->start = orig->start; prealloc->end = split - 1; prealloc->state = orig->state; update_extent_state(prealloc); orig->start = split; update_extent_state(orig); ret = insert_cache_extent(&tree->state, &prealloc->cache_node); BUG_ON(ret); return 0; } /* * clear some bits on a range in the tree. */ static int clear_state_bit(struct extent_io_tree *tree, struct extent_state *state, int bits) { int ret = state->state & bits; state->state &= ~bits; if (state->state == 0) { remove_cache_extent(&tree->state, &state->cache_node); btrfs_free_extent_state(state); } else { merge_state(tree, state); } return ret; } /* * clear some bits on a range in the tree. */ int clear_extent_bits(struct extent_io_tree *tree, u64 start, u64 end, int bits, gfp_t mask) { struct extent_state *state; struct extent_state *prealloc = NULL; struct cache_extent *node; u64 last_end; int err; int set = 0; again: if (!prealloc) { prealloc = alloc_extent_state(); if (!prealloc) return -ENOMEM; } /* * this search will find the extents that end after * our range starts */ node = search_cache_extent(&tree->state, start); if (!node) goto out; state = container_of(node, struct extent_state, cache_node); if (state->start > end) goto out; last_end = state->end; /* * | ---- desired range ---- | * | state | or * | ------------- state -------------- | * * We need to split the extent we found, and may flip * bits on second half. * * If the extent we found extends past our range, we * just split and search again. It'll get split again * the next time though. * * If the extent we found is inside our range, we clear * the desired bit on it. */ if (state->start < start) { err = split_state(tree, state, prealloc, start); BUG_ON(err == -EEXIST); prealloc = NULL; if (err) goto out; if (state->end <= end) { set |= clear_state_bit(tree, state, bits); if (last_end == (u64)-1) goto out; start = last_end + 1; } else { start = state->start; } goto search_again; } /* * | ---- desired range ---- | * | state | * We need to split the extent, and clear the bit * on the first half */ if (state->start <= end && state->end > end) { err = split_state(tree, state, prealloc, end + 1); BUG_ON(err == -EEXIST); set |= clear_state_bit(tree, prealloc, bits); prealloc = NULL; goto out; } start = state->end + 1; set |= clear_state_bit(tree, state, bits); if (last_end == (u64)-1) goto out; start = last_end + 1; goto search_again; out: if (prealloc) btrfs_free_extent_state(prealloc); return set; search_again: if (start > end) goto out; goto again; } /* * set some bits on a range in the tree. */ int set_extent_bits(struct extent_io_tree *tree, u64 start, u64 end, int bits, gfp_t mask) { struct extent_state *state; struct extent_state *prealloc = NULL; struct cache_extent *node; int err = 0; u64 last_start; u64 last_end; again: if (!prealloc) { prealloc = alloc_extent_state(); if (!prealloc) return -ENOMEM; } /* * this search will find the extents that end after * our range starts */ node = search_cache_extent(&tree->state, start); if (!node) { err = insert_state(tree, prealloc, start, end, bits); BUG_ON(err == -EEXIST); prealloc = NULL; goto out; } state = container_of(node, struct extent_state, cache_node); last_start = state->start; last_end = state->end; /* * | ---- desired range ---- | * | state | * * Just lock what we found and keep going */ if (state->start == start && state->end <= end) { state->state |= bits; merge_state(tree, state); if (last_end == (u64)-1) goto out; start = last_end + 1; goto search_again; } /* * | ---- desired range ---- | * | state | * or * | ------------- state -------------- | * * We need to split the extent we found, and may flip bits on * second half. * * If the extent we found extends past our * range, we just split and search again. It'll get split * again the next time though. * * If the extent we found is inside our range, we set the * desired bit on it. */ if (state->start < start) { err = split_state(tree, state, prealloc, start); BUG_ON(err == -EEXIST); prealloc = NULL; if (err) goto out; if (state->end <= end) { state->state |= bits; start = state->end + 1; merge_state(tree, state); if (last_end == (u64)-1) goto out; start = last_end + 1; } else { start = state->start; } goto search_again; } /* * | ---- desired range ---- | * | state | or | state | * * There's a hole, we need to insert something in it and * ignore the extent we found. */ if (state->start > start) { u64 this_end; if (end < last_start) this_end = end; else this_end = last_start -1; err = insert_state(tree, prealloc, start, this_end, bits); BUG_ON(err == -EEXIST); prealloc = NULL; if (err) goto out; start = this_end + 1; goto search_again; } /* * | ---- desired range ---- | * | ---------- state ---------- | * We need to split the extent, and set the bit * on the first half */ err = split_state(tree, state, prealloc, end + 1); BUG_ON(err == -EEXIST); state->state |= bits; merge_state(tree, prealloc); prealloc = NULL; out: if (prealloc) btrfs_free_extent_state(prealloc); return err; search_again: if (start > end) goto out; goto again; } int set_extent_dirty(struct extent_io_tree *tree, u64 start, u64 end, gfp_t mask) { return set_extent_bits(tree, start, end, EXTENT_DIRTY, mask); } int clear_extent_dirty(struct extent_io_tree *tree, u64 start, u64 end, gfp_t mask) { return clear_extent_bits(tree, start, end, EXTENT_DIRTY, mask); } int find_first_extent_bit(struct extent_io_tree *tree, u64 start, u64 *start_ret, u64 *end_ret, int bits) { struct cache_extent *node; struct extent_state *state; int ret = 1; /* * this search will find all the extents that end after * our range starts. */ node = search_cache_extent(&tree->state, start); if (!node) goto out; while(1) { state = container_of(node, struct extent_state, cache_node); if (state->end >= start && (state->state & bits)) { *start_ret = state->start; *end_ret = state->end; ret = 0; break; } node = next_cache_extent(node); if (!node) break; } out: return ret; } int test_range_bit(struct extent_io_tree *tree, u64 start, u64 end, int bits, int filled) { struct extent_state *state = NULL; struct cache_extent *node; int bitset = 0; node = search_cache_extent(&tree->state, start); while (node && start <= end) { state = container_of(node, struct extent_state, cache_node); if (filled && state->start > start) { bitset = 0; break; } if (state->start > end) break; if (state->state & bits) { bitset = 1; if (!filled) break; } else if (filled) { bitset = 0; break; } start = state->end + 1; if (start > end) break; node = next_cache_extent(node); if (!node) { if (filled) bitset = 0; break; } } return bitset; } int set_state_private(struct extent_io_tree *tree, u64 start, u64 private) { struct cache_extent *node; struct extent_state *state; int ret = 0; node = search_cache_extent(&tree->state, start); if (!node) { ret = -ENOENT; goto out; } state = container_of(node, struct extent_state, cache_node); if (state->start != start) { ret = -ENOENT; goto out; } state->xprivate = private; out: return ret; } int get_state_private(struct extent_io_tree *tree, u64 start, u64 *private) { struct cache_extent *node; struct extent_state *state; int ret = 0; node = search_cache_extent(&tree->state, start); if (!node) { ret = -ENOENT; goto out; } state = container_of(node, struct extent_state, cache_node); if (state->start != start) { ret = -ENOENT; goto out; } *private = state->xprivate; out: return ret; } static struct extent_buffer *__alloc_extent_buffer(struct extent_io_tree *tree, u64 bytenr, u32 blocksize) { struct extent_buffer *eb; eb = malloc(sizeof(struct extent_buffer) + blocksize); if (!eb) { BUG(); return NULL; } memset(eb, 0, sizeof(struct extent_buffer) + blocksize); eb->start = bytenr; eb->len = blocksize; eb->refs = 1; eb->flags = 0; eb->tree = tree; eb->fd = -1; eb->dev_bytenr = (u64)-1; eb->cache_node.start = bytenr; eb->cache_node.size = blocksize; INIT_LIST_HEAD(&eb->recow); return eb; } struct extent_buffer *btrfs_clone_extent_buffer(struct extent_buffer *src) { struct extent_buffer *new; new = __alloc_extent_buffer(NULL, src->start, src->len); if (new == NULL) return NULL; copy_extent_buffer(new, src, 0, 0, src->len); new->flags |= EXTENT_BUFFER_DUMMY; return new; } void free_extent_buffer(struct extent_buffer *eb) { if (!eb) return; eb->refs--; BUG_ON(eb->refs < 0); if (eb->refs == 0) { struct extent_io_tree *tree = eb->tree; BUG_ON(eb->flags & EXTENT_DIRTY); list_del_init(&eb->lru); list_del_init(&eb->recow); if (!(eb->flags & EXTENT_BUFFER_DUMMY)) { BUG_ON(tree->cache_size < eb->len); remove_cache_extent(&tree->cache, &eb->cache_node); tree->cache_size -= eb->len; } free(eb); } } struct extent_buffer *find_extent_buffer(struct extent_io_tree *tree, u64 bytenr, u32 blocksize) { struct extent_buffer *eb = NULL; struct cache_extent *cache; cache = lookup_cache_extent(&tree->cache, bytenr, blocksize); if (cache && cache->start == bytenr && cache->size == blocksize) { eb = container_of(cache, struct extent_buffer, cache_node); list_move_tail(&eb->lru, &tree->lru); eb->refs++; } return eb; } struct extent_buffer *find_first_extent_buffer(struct extent_io_tree *tree, u64 start) { struct extent_buffer *eb = NULL; struct cache_extent *cache; cache = search_cache_extent(&tree->cache, start); if (cache) { eb = container_of(cache, struct extent_buffer, cache_node); list_move_tail(&eb->lru, &tree->lru); eb->refs++; } return eb; } struct extent_buffer *alloc_extent_buffer(struct extent_io_tree *tree, u64 bytenr, u32 blocksize) { struct extent_buffer *eb; struct cache_extent *cache; cache = lookup_cache_extent(&tree->cache, bytenr, blocksize); if (cache && cache->start == bytenr && cache->size == blocksize) { eb = container_of(cache, struct extent_buffer, cache_node); list_move_tail(&eb->lru, &tree->lru); eb->refs++; } else { int ret; if (cache) { eb = container_of(cache, struct extent_buffer, cache_node); free_extent_buffer(eb); } eb = __alloc_extent_buffer(tree, bytenr, blocksize); if (!eb) return NULL; ret = insert_cache_extent(&tree->cache, &eb->cache_node); if (ret) { free(eb); return NULL; } list_add_tail(&eb->lru, &tree->lru); tree->cache_size += blocksize; } return eb; } int read_extent_from_disk(struct extent_buffer *eb, unsigned long offset, unsigned long len) { int ret; ret = pread(eb->fd, eb->data + offset, len, eb->dev_bytenr); if (ret < 0) { ret = -errno; goto out; } if (ret != len) { ret = -EIO; goto out; } ret = 0; out: return ret; } int write_extent_to_disk(struct extent_buffer *eb) { int ret; ret = pwrite(eb->fd, eb->data, eb->len, eb->dev_bytenr); if (ret < 0) goto out; if (ret != eb->len) { ret = -EIO; goto out; } ret = 0; out: return ret; } int read_data_from_disk(struct btrfs_fs_info *info, void *buf, u64 offset, u64 bytes, int mirror) { struct btrfs_multi_bio *multi = NULL; struct btrfs_device *device; u64 bytes_left = bytes; u64 read_len; u64 total_read = 0; int ret; while (bytes_left) { read_len = bytes_left; ret = btrfs_map_block(&info->mapping_tree, READ, offset, &read_len, &multi, mirror, NULL); if (ret) { fprintf(stderr, "Couldn't map the block %Lu\n", offset); return -EIO; } device = multi->stripes[0].dev; read_len = min(bytes_left, read_len); if (device->fd == 0) { kfree(multi); return -EIO; } ret = pread(device->fd, buf + total_read, read_len, multi->stripes[0].physical); kfree(multi); if (ret < 0) { fprintf(stderr, "Error reading %Lu, %d\n", offset, ret); return ret; } if (ret != read_len) { fprintf(stderr, "Short read for %Lu, read %d, " "read_len %Lu\n", offset, ret, read_len); return -EIO; } bytes_left -= read_len; offset += read_len; total_read += read_len; } return 0; } int write_data_to_disk(struct btrfs_fs_info *info, void *buf, u64 offset, u64 bytes, int mirror) { struct btrfs_multi_bio *multi = NULL; struct btrfs_device *device; u64 bytes_left = bytes; u64 this_len; u64 total_write = 0; u64 *raid_map = NULL; u64 dev_bytenr; int dev_nr; int ret = 0; while (bytes_left > 0) { this_len = bytes_left; dev_nr = 0; ret = btrfs_map_block(&info->mapping_tree, WRITE, offset, &this_len, &multi, mirror, &raid_map); if (ret) { fprintf(stderr, "Couldn't map the block %Lu\n", offset); return -EIO; } if (raid_map) { struct extent_buffer *eb; u64 stripe_len = this_len; this_len = min(this_len, bytes_left); this_len = min(this_len, (u64)info->tree_root->leafsize); eb = malloc(sizeof(struct extent_buffer) + this_len); BUG_ON(!eb); memset(eb, 0, sizeof(struct extent_buffer) + this_len); eb->start = offset; eb->len = this_len; memcpy(eb->data, buf + total_write, this_len); ret = write_raid56_with_parity(info, eb, multi, stripe_len, raid_map); BUG_ON(ret); free(eb); kfree(raid_map); raid_map = NULL; } else while (dev_nr < multi->num_stripes) { device = multi->stripes[dev_nr].dev; if (device->fd == 0) { kfree(multi); return -EIO; } dev_bytenr = multi->stripes[dev_nr].physical; this_len = min(this_len, bytes_left); dev_nr++; ret = pwrite(device->fd, buf + total_write, this_len, dev_bytenr); if (ret != this_len) { if (ret < 0) { fprintf(stderr, "Error writing to " "device %d\n", errno); ret = errno; kfree(multi); return ret; } else { fprintf(stderr, "Short write\n"); kfree(multi); return -EIO; } } } BUG_ON(bytes_left < this_len); bytes_left -= this_len; offset += this_len; total_write += this_len; kfree(multi); multi = NULL; } return 0; } int set_extent_buffer_uptodate(struct extent_buffer *eb) { eb->flags |= EXTENT_UPTODATE; return 0; } int clear_extent_buffer_uptodate(struct extent_io_tree *tree, struct extent_buffer *eb) { eb->flags &= ~EXTENT_UPTODATE; return 0; } int extent_buffer_uptodate(struct extent_buffer *eb) { if (!eb) return 0; if (eb->flags & EXTENT_UPTODATE) return 1; return 0; } int set_extent_buffer_dirty(struct extent_buffer *eb) { struct extent_io_tree *tree = eb->tree; if (!(eb->flags & EXTENT_DIRTY)) { eb->flags |= EXTENT_DIRTY; set_extent_dirty(tree, eb->start, eb->start + eb->len - 1, 0); extent_buffer_get(eb); } return 0; } int clear_extent_buffer_dirty(struct extent_buffer *eb) { struct extent_io_tree *tree = eb->tree; if (eb->flags & EXTENT_DIRTY) { eb->flags &= ~EXTENT_DIRTY; clear_extent_dirty(tree, eb->start, eb->start + eb->len - 1, 0); free_extent_buffer(eb); } return 0; } int memcmp_extent_buffer(struct extent_buffer *eb, const void *ptrv, unsigned long start, unsigned long len) { return memcmp(eb->data + start, ptrv, len); } void read_extent_buffer(struct extent_buffer *eb, void *dst, unsigned long start, unsigned long len) { memcpy(dst, eb->data + start, len); } void write_extent_buffer(struct extent_buffer *eb, const void *src, unsigned long start, unsigned long len) { memcpy(eb->data + start, src, len); } void copy_extent_buffer(struct extent_buffer *dst, struct extent_buffer *src, unsigned long dst_offset, unsigned long src_offset, unsigned long len) { memcpy(dst->data + dst_offset, src->data + src_offset, len); } void memmove_extent_buffer(struct extent_buffer *dst, unsigned long dst_offset, unsigned long src_offset, unsigned long len) { memmove(dst->data + dst_offset, dst->data + src_offset, len); } void memset_extent_buffer(struct extent_buffer *eb, char c, unsigned long start, unsigned long len) { memset(eb->data + start, c, len); } partclone-0.2.86/src/btrfs/extent_io.h000066400000000000000000000114141262102574200176560ustar00rootroot00000000000000/* * Copyright (C) 2007 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. */ #ifndef __EXTENTMAP__ #define __EXTENTMAP__ #if BTRFS_FLAT_INCLUDES #include "kerncompat.h" #include "extent-cache.h" #include "list.h" #else #include #include #include #endif /* BTRFS_FLAT_INCLUDES */ #define EXTENT_DIRTY 1 #define EXTENT_WRITEBACK (1 << 1) #define EXTENT_UPTODATE (1 << 2) #define EXTENT_LOCKED (1 << 3) #define EXTENT_NEW (1 << 4) #define EXTENT_DELALLOC (1 << 5) #define EXTENT_DEFRAG (1 << 6) #define EXTENT_DEFRAG_DONE (1 << 7) #define EXTENT_BUFFER_FILLED (1 << 8) #define EXTENT_CSUM (1 << 9) #define EXTENT_BAD_TRANSID (1 << 10) #define EXTENT_BUFFER_DUMMY (1 << 11) #define EXTENT_IOBITS (EXTENT_LOCKED | EXTENT_WRITEBACK) #define BLOCK_GROUP_DATA EXTENT_WRITEBACK #define BLOCK_GROUP_METADATA EXTENT_UPTODATE #define BLOCK_GROUP_SYSTEM EXTENT_NEW #define BLOCK_GROUP_DIRTY EXTENT_DIRTY struct btrfs_fs_info; struct extent_io_tree { struct cache_tree state; struct cache_tree cache; struct list_head lru; u64 cache_size; }; struct extent_state { struct cache_extent cache_node; u64 start; u64 end; int refs; unsigned long state; u64 xprivate; }; struct extent_buffer { struct cache_extent cache_node; u64 start; u64 dev_bytenr; u32 len; struct extent_io_tree *tree; struct list_head lru; struct list_head recow; int refs; int flags; int fd; char data[]; }; static inline void extent_buffer_get(struct extent_buffer *eb) { eb->refs++; } void extent_io_tree_init(struct extent_io_tree *tree); void extent_io_tree_cleanup(struct extent_io_tree *tree); int set_extent_bits(struct extent_io_tree *tree, u64 start, u64 end, int bits, gfp_t mask); int clear_extent_bits(struct extent_io_tree *tree, u64 start, u64 end, int bits, gfp_t mask); int find_first_extent_bit(struct extent_io_tree *tree, u64 start, u64 *start_ret, u64 *end_ret, int bits); int test_range_bit(struct extent_io_tree *tree, u64 start, u64 end, int bits, int filled); int set_extent_dirty(struct extent_io_tree *tree, u64 start, u64 end, gfp_t mask); int clear_extent_dirty(struct extent_io_tree *tree, u64 start, u64 end, gfp_t mask); int extent_buffer_uptodate(struct extent_buffer *eb); int set_extent_buffer_uptodate(struct extent_buffer *eb); int clear_extent_buffer_uptodate(struct extent_io_tree *tree, struct extent_buffer *eb); int set_state_private(struct extent_io_tree *tree, u64 start, u64 xprivate); int get_state_private(struct extent_io_tree *tree, u64 start, u64 *xprivate); struct extent_buffer *find_extent_buffer(struct extent_io_tree *tree, u64 bytenr, u32 blocksize); struct extent_buffer *find_first_extent_buffer(struct extent_io_tree *tree, u64 start); struct extent_buffer *alloc_extent_buffer(struct extent_io_tree *tree, u64 bytenr, u32 blocksize); struct extent_buffer *btrfs_clone_extent_buffer(struct extent_buffer *src); void free_extent_buffer(struct extent_buffer *eb); int read_extent_from_disk(struct extent_buffer *eb, unsigned long offset, unsigned long len); int write_extent_to_disk(struct extent_buffer *eb); int memcmp_extent_buffer(struct extent_buffer *eb, const void *ptrv, unsigned long start, unsigned long len); void read_extent_buffer(struct extent_buffer *eb, void *dst, unsigned long start, unsigned long len); void write_extent_buffer(struct extent_buffer *eb, const void *src, unsigned long start, unsigned long len); void copy_extent_buffer(struct extent_buffer *dst, struct extent_buffer *src, unsigned long dst_offset, unsigned long src_offset, unsigned long len); void memmove_extent_buffer(struct extent_buffer *dst, unsigned long dst_offset, unsigned long src_offset, unsigned long len); void memset_extent_buffer(struct extent_buffer *eb, char c, unsigned long start, unsigned long len); int set_extent_buffer_dirty(struct extent_buffer *eb); int clear_extent_buffer_dirty(struct extent_buffer *eb); int read_data_from_disk(struct btrfs_fs_info *info, void *buf, u64 offset, u64 bytes, int mirror); int write_data_to_disk(struct btrfs_fs_info *info, void *buf, u64 offset, u64 bytes, int mirror); #endif partclone-0.2.86/src/btrfs/file-item.c000066400000000000000000000322171262102574200175320ustar00rootroot00000000000000/* * Copyright (C) 2007 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. */ #include #include #include "kerncompat.h" #include "radix-tree.h" #include "ctree.h" #include "disk-io.h" #include "transaction.h" #include "print-tree.h" #include "crc32c.h" #define MAX_CSUM_ITEMS(r,size) ((((BTRFS_LEAF_DATA_SIZE(r) - \ sizeof(struct btrfs_item) * 2) / \ size) - 1)) int btrfs_insert_file_extent(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 objectid, u64 pos, u64 offset, u64 disk_num_bytes, u64 num_bytes) { int ret = 0; struct btrfs_file_extent_item *item; struct btrfs_key file_key; struct btrfs_path *path; struct extent_buffer *leaf; path = btrfs_alloc_path(); BUG_ON(!path); file_key.objectid = objectid; file_key.offset = pos; btrfs_set_key_type(&file_key, BTRFS_EXTENT_DATA_KEY); ret = btrfs_insert_empty_item(trans, root, path, &file_key, sizeof(*item)); if (ret < 0) goto out; BUG_ON(ret); leaf = path->nodes[0]; item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_file_extent_item); btrfs_set_file_extent_disk_bytenr(leaf, item, offset); btrfs_set_file_extent_disk_num_bytes(leaf, item, disk_num_bytes); btrfs_set_file_extent_offset(leaf, item, 0); btrfs_set_file_extent_num_bytes(leaf, item, num_bytes); btrfs_set_file_extent_ram_bytes(leaf, item, num_bytes); btrfs_set_file_extent_generation(leaf, item, trans->transid); btrfs_set_file_extent_type(leaf, item, BTRFS_FILE_EXTENT_REG); btrfs_set_file_extent_compression(leaf, item, 0); btrfs_set_file_extent_encryption(leaf, item, 0); btrfs_set_file_extent_other_encoding(leaf, item, 0); btrfs_mark_buffer_dirty(leaf); out: btrfs_free_path(path); return ret; } int btrfs_insert_inline_extent(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 objectid, u64 offset, char *buffer, size_t size) { struct btrfs_key key; struct btrfs_path *path; struct extent_buffer *leaf; unsigned long ptr; struct btrfs_file_extent_item *ei; u32 datasize; int err = 0; int ret; path = btrfs_alloc_path(); if (!path) return -ENOMEM; key.objectid = objectid; key.offset = offset; btrfs_set_key_type(&key, BTRFS_EXTENT_DATA_KEY); datasize = btrfs_file_extent_calc_inline_size(size); ret = btrfs_insert_empty_item(trans, root, path, &key, datasize); if (ret) { err = ret; goto fail; } leaf = path->nodes[0]; ei = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_file_extent_item); btrfs_set_file_extent_generation(leaf, ei, trans->transid); btrfs_set_file_extent_type(leaf, ei, BTRFS_FILE_EXTENT_INLINE); btrfs_set_file_extent_ram_bytes(leaf, ei, size); btrfs_set_file_extent_compression(leaf, ei, 0); btrfs_set_file_extent_encryption(leaf, ei, 0); btrfs_set_file_extent_other_encoding(leaf, ei, 0); ptr = btrfs_file_extent_inline_start(ei) + offset - key.offset; write_extent_buffer(leaf, buffer, ptr, size); btrfs_mark_buffer_dirty(leaf); fail: btrfs_free_path(path); return err; } static struct btrfs_csum_item * btrfs_lookup_csum(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, u64 bytenr, int cow) { int ret; struct btrfs_key file_key; struct btrfs_key found_key; struct btrfs_csum_item *item; struct extent_buffer *leaf; u64 csum_offset = 0; u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy); int csums_in_item; file_key.objectid = BTRFS_EXTENT_CSUM_OBJECTID; file_key.offset = bytenr; btrfs_set_key_type(&file_key, BTRFS_EXTENT_CSUM_KEY); ret = btrfs_search_slot(trans, root, &file_key, path, 0, cow); if (ret < 0) goto fail; leaf = path->nodes[0]; if (ret > 0) { ret = 1; if (path->slots[0] == 0) goto fail; path->slots[0]--; btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); if (btrfs_key_type(&found_key) != BTRFS_EXTENT_CSUM_KEY) goto fail; csum_offset = (bytenr - found_key.offset) / root->sectorsize; csums_in_item = btrfs_item_size_nr(leaf, path->slots[0]); csums_in_item /= csum_size; if (csum_offset >= csums_in_item) { ret = -EFBIG; goto fail; } } item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_csum_item); item = (struct btrfs_csum_item *)((unsigned char *)item + csum_offset * csum_size); return item; fail: if (ret > 0) ret = -ENOENT; return ERR_PTR(ret); } int btrfs_csum_file_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 alloc_end, u64 bytenr, char *data, size_t len) { int ret = 0; struct btrfs_key file_key; struct btrfs_key found_key; u64 next_offset = (u64)-1; int found_next = 0; struct btrfs_path *path; struct btrfs_csum_item *item; struct extent_buffer *leaf = NULL; u64 csum_offset; u32 csum_result = ~(u32)0; u32 nritems; u32 ins_size; u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy); path = btrfs_alloc_path(); BUG_ON(!path); file_key.objectid = BTRFS_EXTENT_CSUM_OBJECTID; file_key.offset = bytenr; file_key.type = BTRFS_EXTENT_CSUM_KEY; item = btrfs_lookup_csum(trans, root, path, bytenr, 1); if (!IS_ERR(item)) { leaf = path->nodes[0]; ret = 0; goto found; } ret = PTR_ERR(item); if (ret == -EFBIG) { u32 item_size; /* we found one, but it isn't big enough yet */ leaf = path->nodes[0]; item_size = btrfs_item_size_nr(leaf, path->slots[0]); if ((item_size / csum_size) >= MAX_CSUM_ITEMS(root, csum_size)) { /* already at max size, make a new one */ goto insert; } } else { int slot = path->slots[0] + 1; /* we didn't find a csum item, insert one */ nritems = btrfs_header_nritems(path->nodes[0]); if (path->slots[0] >= nritems - 1) { ret = btrfs_next_leaf(root, path); if (ret == 1) found_next = 1; if (ret != 0) goto insert; slot = 0; } btrfs_item_key_to_cpu(path->nodes[0], &found_key, slot); if (found_key.objectid != BTRFS_EXTENT_CSUM_OBJECTID || found_key.type != BTRFS_EXTENT_CSUM_KEY) { found_next = 1; goto insert; } next_offset = found_key.offset; found_next = 1; goto insert; } /* * at this point, we know the tree has an item, but it isn't big * enough yet to put our csum in. Grow it */ btrfs_release_path(path); ret = btrfs_search_slot(trans, root, &file_key, path, csum_size, 1); if (ret < 0) goto fail; if (ret == 0) { BUG(); } if (path->slots[0] == 0) { goto insert; } path->slots[0]--; leaf = path->nodes[0]; btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); csum_offset = (file_key.offset - found_key.offset) / root->sectorsize; if (found_key.objectid != BTRFS_EXTENT_CSUM_OBJECTID || found_key.type != BTRFS_EXTENT_CSUM_KEY || csum_offset >= MAX_CSUM_ITEMS(root, csum_size)) { goto insert; } if (csum_offset >= btrfs_item_size_nr(leaf, path->slots[0]) / csum_size) { u32 diff = (csum_offset + 1) * csum_size; diff = diff - btrfs_item_size_nr(leaf, path->slots[0]); if (diff != csum_size) goto insert; ret = btrfs_extend_item(trans, root, path, diff); BUG_ON(ret); goto csum; } insert: btrfs_release_path(path); csum_offset = 0; if (found_next) { u64 tmp = min(alloc_end, next_offset); tmp -= file_key.offset; tmp /= root->sectorsize; tmp = max((u64)1, tmp); tmp = min(tmp, (u64)MAX_CSUM_ITEMS(root, csum_size)); ins_size = csum_size * tmp; } else { ins_size = csum_size; } ret = btrfs_insert_empty_item(trans, root, path, &file_key, ins_size); if (ret < 0) goto fail; if (ret != 0) { WARN_ON(1); goto fail; } csum: leaf = path->nodes[0]; item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_csum_item); ret = 0; item = (struct btrfs_csum_item *)((unsigned char *)item + csum_offset * csum_size); found: csum_result = btrfs_csum_data(root, data, csum_result, len); btrfs_csum_final(csum_result, (char *)&csum_result); if (csum_result == 0) { printk("csum result is 0 for block %llu\n", (unsigned long long)bytenr); } write_extent_buffer(leaf, &csum_result, (unsigned long)item, csum_size); btrfs_mark_buffer_dirty(path->nodes[0]); fail: btrfs_free_path(path); return ret; } /* * helper function for csum removal, this expects the * key to describe the csum pointed to by the path, and it expects * the csum to overlap the range [bytenr, len] * * The csum should not be entirely contained in the range and the * range should not be entirely contained in the csum. * * This calls btrfs_truncate_item with the correct args based on the * overlap, and fixes up the key as required. */ static noinline int truncate_one_csum(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, struct btrfs_key *key, u64 bytenr, u64 len) { struct extent_buffer *leaf; u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy); u64 csum_end; u64 end_byte = bytenr + len; u32 blocksize = root->sectorsize; int ret; leaf = path->nodes[0]; csum_end = btrfs_item_size_nr(leaf, path->slots[0]) / csum_size; csum_end *= root->sectorsize; csum_end += key->offset; if (key->offset < bytenr && csum_end <= end_byte) { /* * [ bytenr - len ] * [ ] * [csum ] * A simple truncate off the end of the item */ u32 new_size = (bytenr - key->offset) / blocksize; new_size *= csum_size; ret = btrfs_truncate_item(trans, root, path, new_size, 1); BUG_ON(ret); } else if (key->offset >= bytenr && csum_end > end_byte && end_byte > key->offset) { /* * [ bytenr - len ] * [ ] * [csum ] * we need to truncate from the beginning of the csum */ u32 new_size = (csum_end - end_byte) / blocksize; new_size *= csum_size; ret = btrfs_truncate_item(trans, root, path, new_size, 0); BUG_ON(ret); key->offset = end_byte; ret = btrfs_set_item_key_safe(root, path, key); BUG_ON(ret); } else { BUG(); } return 0; } /* * deletes the csum items from the csum tree for a given * range of bytes. */ int btrfs_del_csums(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 bytenr, u64 len) { struct btrfs_path *path; struct btrfs_key key; u64 end_byte = bytenr + len; u64 csum_end; struct extent_buffer *leaf; int ret; u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy); int blocksize = root->sectorsize; root = root->fs_info->csum_root; path = btrfs_alloc_path(); if (!path) return -ENOMEM; while (1) { key.objectid = BTRFS_EXTENT_CSUM_OBJECTID; key.offset = end_byte - 1; key.type = BTRFS_EXTENT_CSUM_KEY; ret = btrfs_search_slot(trans, root, &key, path, -1, 1); if (ret > 0) { if (path->slots[0] == 0) goto out; path->slots[0]--; } leaf = path->nodes[0]; btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); if (key.objectid != BTRFS_EXTENT_CSUM_OBJECTID || key.type != BTRFS_EXTENT_CSUM_KEY) { break; } if (key.offset >= end_byte) break; csum_end = btrfs_item_size_nr(leaf, path->slots[0]) / csum_size; csum_end *= blocksize; csum_end += key.offset; /* this csum ends before we start, we're done */ if (csum_end <= bytenr) break; /* delete the entire item, it is inside our range */ if (key.offset >= bytenr && csum_end <= end_byte) { ret = btrfs_del_item(trans, root, path); BUG_ON(ret); } else if (key.offset < bytenr && csum_end > end_byte) { unsigned long offset; unsigned long shift_len; unsigned long item_offset; /* * [ bytenr - len ] * [csum ] * * Our bytes are in the middle of the csum, * we need to split this item and insert a new one. * * But we can't drop the path because the * csum could change, get removed, extended etc. * * The trick here is the max size of a csum item leaves * enough room in the tree block for a single * item header. So, we split the item in place, * adding a new header pointing to the existing * bytes. Then we loop around again and we have * a nicely formed csum item that we can neatly * truncate. */ offset = (bytenr - key.offset) / blocksize; offset *= csum_size; shift_len = (len / blocksize) * csum_size; item_offset = btrfs_item_ptr_offset(leaf, path->slots[0]); memset_extent_buffer(leaf, 0, item_offset + offset, shift_len); key.offset = bytenr; /* * btrfs_split_item returns -EAGAIN when the * item changed size or key */ ret = btrfs_split_item(trans, root, path, &key, offset); BUG_ON(ret && ret != -EAGAIN); key.offset = end_byte - 1; } else { ret = truncate_one_csum(trans, root, path, &key, bytenr, len); BUG_ON(ret); } btrfs_release_path(path); } out: btrfs_free_path(path); return 0; } partclone-0.2.86/src/btrfs/free-space-cache.c000066400000000000000000000510771262102574200207370ustar00rootroot00000000000000/* * Copyright (C) 2008 Red Hat. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. */ #include "kerncompat.h" #include "ctree.h" #include "free-space-cache.h" #include "transaction.h" #include "disk-io.h" #include "extent_io.h" #include "crc32c.h" #include "bitops.h" /* * Kernel always uses PAGE_CACHE_SIZE for sectorsize, but we don't have * anything like that in userspace and have to get the value from the * filesystem */ #define BITS_PER_BITMAP(sectorsize) ((sectorsize) * 8) #define MAX_CACHE_BYTES_PER_GIG (32 * 1024) static int link_free_space(struct btrfs_free_space_ctl *ctl, struct btrfs_free_space *info); static void merge_space_tree(struct btrfs_free_space_ctl *ctl); struct io_ctl { void *cur, *orig; void *buffer; struct btrfs_root *root; unsigned long size; u64 total_size; int index; int num_pages; unsigned check_crcs:1; }; static int io_ctl_init(struct io_ctl *io_ctl, u64 size, u64 ino, struct btrfs_root *root) { memset(io_ctl, 0, sizeof(struct io_ctl)); io_ctl->num_pages = (size + root->sectorsize - 1) / root->sectorsize; io_ctl->buffer = kzalloc(size, GFP_NOFS); if (!io_ctl->buffer) return -ENOMEM; io_ctl->total_size = size; io_ctl->root = root; if (ino != BTRFS_FREE_INO_OBJECTID) io_ctl->check_crcs = 1; return 0; } static void io_ctl_free(struct io_ctl *io_ctl) { kfree(io_ctl->buffer); } static void io_ctl_unmap_page(struct io_ctl *io_ctl) { if (io_ctl->cur) { io_ctl->cur = NULL; io_ctl->orig = NULL; } } static void io_ctl_map_page(struct io_ctl *io_ctl, int clear) { BUG_ON(io_ctl->index >= io_ctl->num_pages); io_ctl->cur = io_ctl->buffer + (io_ctl->index++ * io_ctl->root->sectorsize); io_ctl->orig = io_ctl->cur; io_ctl->size = io_ctl->root->sectorsize; if (clear) memset(io_ctl->cur, 0, io_ctl->root->sectorsize); } static void io_ctl_drop_pages(struct io_ctl *io_ctl) { io_ctl_unmap_page(io_ctl); } static int io_ctl_prepare_pages(struct io_ctl *io_ctl, struct btrfs_root *root, struct btrfs_path *path, u64 ino) { struct extent_buffer *leaf; struct btrfs_file_extent_item *fi; struct btrfs_key key; u64 bytenr, len; u64 total_read = 0; int ret = 0; key.objectid = ino; key.type = BTRFS_EXTENT_DATA_KEY; key.offset = 0; ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); if (ret) { printf("Couldn't find file extent item for free space inode" " %Lu\n", ino); btrfs_release_path(path); return -EINVAL; } while (total_read < io_ctl->total_size) { if (path->slots[0] >= btrfs_header_nritems(path->nodes[0])) { ret = btrfs_next_leaf(root, path); if (ret) { ret = -EINVAL; break; } } leaf = path->nodes[0]; btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); if (key.objectid != ino) { ret = -EINVAL; break; } if (key.type != BTRFS_EXTENT_DATA_KEY) { ret = -EINVAL; break; } fi = btrfs_item_ptr(path->nodes[0], path->slots[0], struct btrfs_file_extent_item); if (btrfs_file_extent_type(path->nodes[0], fi) != BTRFS_FILE_EXTENT_REG) { printf("Not the file extent type we wanted\n"); ret = -EINVAL; break; } bytenr = btrfs_file_extent_disk_bytenr(leaf, fi) + btrfs_file_extent_offset(leaf, fi); len = btrfs_file_extent_num_bytes(leaf, fi); ret = read_data_from_disk(root->fs_info, io_ctl->buffer + key.offset, bytenr, len, 0); if (ret) break; total_read += len; path->slots[0]++; } btrfs_release_path(path); return ret; } static int io_ctl_check_generation(struct io_ctl *io_ctl, u64 generation) { __le64 *gen; /* * Skip the crc area. If we don't check crcs then we just have a 64bit * chunk at the front of the first page. */ if (io_ctl->check_crcs) { io_ctl->cur += sizeof(u32) * io_ctl->num_pages; io_ctl->size -= sizeof(u64) + (sizeof(u32) * io_ctl->num_pages); } else { io_ctl->cur += sizeof(u64); io_ctl->size -= sizeof(u64) * 2; } gen = io_ctl->cur; if (le64_to_cpu(*gen) != generation) { printk("btrfs: space cache generation " "(%Lu) does not match inode (%Lu)\n", *gen, generation); io_ctl_unmap_page(io_ctl); return -EIO; } io_ctl->cur += sizeof(u64); return 0; } static int io_ctl_check_crc(struct io_ctl *io_ctl, int index) { u32 *tmp, val; u32 crc = ~(u32)0; unsigned offset = 0; if (!io_ctl->check_crcs) { io_ctl_map_page(io_ctl, 0); return 0; } if (index == 0) offset = sizeof(u32) * io_ctl->num_pages; tmp = io_ctl->buffer; tmp += index; val = *tmp; io_ctl_map_page(io_ctl, 0); crc = crc32c(crc, io_ctl->orig + offset, io_ctl->root->sectorsize - offset); btrfs_csum_final(crc, (char *)&crc); if (val != crc) { printk("btrfs: csum mismatch on free space cache\n"); io_ctl_unmap_page(io_ctl); return -EIO; } return 0; } static int io_ctl_read_entry(struct io_ctl *io_ctl, struct btrfs_free_space *entry, u8 *type) { struct btrfs_free_space_entry *e; int ret; if (!io_ctl->cur) { ret = io_ctl_check_crc(io_ctl, io_ctl->index); if (ret) return ret; } e = io_ctl->cur; entry->offset = le64_to_cpu(e->offset); entry->bytes = le64_to_cpu(e->bytes); *type = e->type; io_ctl->cur += sizeof(struct btrfs_free_space_entry); io_ctl->size -= sizeof(struct btrfs_free_space_entry); if (io_ctl->size >= sizeof(struct btrfs_free_space_entry)) return 0; io_ctl_unmap_page(io_ctl); return 0; } static int io_ctl_read_bitmap(struct io_ctl *io_ctl, struct btrfs_free_space *entry) { int ret; ret = io_ctl_check_crc(io_ctl, io_ctl->index); if (ret) return ret; memcpy(entry->bitmap, io_ctl->cur, io_ctl->root->sectorsize); io_ctl_unmap_page(io_ctl); return 0; } static int __load_free_space_cache(struct btrfs_root *root, struct btrfs_free_space_ctl *ctl, struct btrfs_path *path, u64 offset) { struct btrfs_free_space_header *header; struct btrfs_inode_item *inode_item; struct extent_buffer *leaf; struct io_ctl io_ctl; struct btrfs_key key; struct btrfs_key inode_location; struct btrfs_disk_key disk_key; struct btrfs_free_space *e, *n; struct list_head bitmaps; u64 num_entries; u64 num_bitmaps; u64 generation; u64 inode_size; u8 type; int ret = 0; INIT_LIST_HEAD(&bitmaps); key.objectid = BTRFS_FREE_SPACE_OBJECTID; key.offset = offset; key.type = 0; ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); if (ret < 0) { return 0; } else if (ret > 0) { btrfs_release_path(path); return 0; } leaf = path->nodes[0]; header = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_free_space_header); num_entries = btrfs_free_space_entries(leaf, header); num_bitmaps = btrfs_free_space_bitmaps(leaf, header); generation = btrfs_free_space_generation(leaf, header); btrfs_free_space_key(leaf, header, &disk_key); btrfs_disk_key_to_cpu(&inode_location, &disk_key); btrfs_release_path(path); ret = btrfs_search_slot(NULL, root, &inode_location, path, 0, 0); if (ret) { printf("Couldn't find free space inode %d\n", ret); return 0; } leaf = path->nodes[0]; inode_item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_inode_item); inode_size = btrfs_inode_size(leaf, inode_item); if (!inode_size || !btrfs_inode_generation(leaf, inode_item)) { btrfs_release_path(path); return 0; } if (btrfs_inode_generation(leaf, inode_item) != generation) { printf("free space inode generation (%llu) did not match " "free space cache generation (%llu)\n", (unsigned long long)btrfs_inode_generation(leaf, inode_item), (unsigned long long)generation); btrfs_release_path(path); return 0; } btrfs_release_path(path); if (!num_entries) return 0; ret = io_ctl_init(&io_ctl, inode_size, inode_location.objectid, root); if (ret) return ret; ret = io_ctl_prepare_pages(&io_ctl, root, path, inode_location.objectid); if (ret) goto out; ret = io_ctl_check_crc(&io_ctl, 0); if (ret) goto free_cache; ret = io_ctl_check_generation(&io_ctl, generation); if (ret) goto free_cache; while (num_entries) { e = calloc(1, sizeof(*e)); if (!e) goto free_cache; ret = io_ctl_read_entry(&io_ctl, e, &type); if (ret) { free(e); goto free_cache; } if (!e->bytes) { free(e); goto free_cache; } if (type == BTRFS_FREE_SPACE_EXTENT) { ret = link_free_space(ctl, e); if (ret) { printf("Duplicate entries in free space cache, dumping"); free(e); goto free_cache; } } else { BUG_ON(!num_bitmaps); num_bitmaps--; e->bitmap = kzalloc(ctl->sectorsize, GFP_NOFS); if (!e->bitmap) { free(e); goto free_cache; } ret = link_free_space(ctl, e); ctl->total_bitmaps++; if (ret) { printf("Duplicate entries in free space cache, dumping"); free(e->bitmap); free(e); goto free_cache; } list_add_tail(&e->list, &bitmaps); } num_entries--; } io_ctl_unmap_page(&io_ctl); /* * We add the bitmaps at the end of the entries in order that * the bitmap entries are added to the cache. */ list_for_each_entry_safe(e, n, &bitmaps, list) { list_del_init(&e->list); ret = io_ctl_read_bitmap(&io_ctl, e); if (ret) goto free_cache; } io_ctl_drop_pages(&io_ctl); merge_space_tree(ctl); ret = 1; out: io_ctl_free(&io_ctl); return ret; free_cache: io_ctl_drop_pages(&io_ctl); __btrfs_remove_free_space_cache(ctl); goto out; } int load_free_space_cache(struct btrfs_fs_info *fs_info, struct btrfs_block_group_cache *block_group) { struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl; struct btrfs_path *path; int ret = 0; path = btrfs_alloc_path(); if (!path) return 0; ret = __load_free_space_cache(fs_info->tree_root, ctl, path, block_group->key.objectid); btrfs_free_path(path); if (ret < 0) { ret = 0; printf("failed to load free space cache for block group %llu\n", block_group->key.objectid); } return ret; } static inline unsigned long offset_to_bit(u64 bitmap_start, u32 unit, u64 offset) { BUG_ON(offset < bitmap_start); offset -= bitmap_start; return (unsigned long)(offset / unit); } static inline unsigned long bytes_to_bits(u64 bytes, u32 unit) { return (unsigned long)(bytes / unit); } static inline u64 offset_to_bitmap(struct btrfs_free_space_ctl *ctl, u64 offset) { u64 bitmap_start; u64 bytes_per_bitmap; u32 sectorsize = ctl->sectorsize; bytes_per_bitmap = BITS_PER_BITMAP(sectorsize) * ctl->unit; bitmap_start = offset - ctl->start; bitmap_start = bitmap_start / bytes_per_bitmap; bitmap_start *= bytes_per_bitmap; bitmap_start += ctl->start; return bitmap_start; } static int tree_insert_offset(struct rb_root *root, u64 offset, struct rb_node *node, int bitmap) { struct rb_node **p = &root->rb_node; struct rb_node *parent = NULL; struct btrfs_free_space *info; while (*p) { parent = *p; info = rb_entry(parent, struct btrfs_free_space, offset_index); if (offset < info->offset) { p = &(*p)->rb_left; } else if (offset > info->offset) { p = &(*p)->rb_right; } else { /* * we could have a bitmap entry and an extent entry * share the same offset. If this is the case, we want * the extent entry to always be found first if we do a * linear search through the tree, since we want to have * the quickest allocation time, and allocating from an * extent is faster than allocating from a bitmap. So * if we're inserting a bitmap and we find an entry at * this offset, we want to go right, or after this entry * logically. If we are inserting an extent and we've * found a bitmap, we want to go left, or before * logically. */ if (bitmap) { if (info->bitmap) return -EEXIST; p = &(*p)->rb_right; } else { if (!info->bitmap) return -EEXIST; p = &(*p)->rb_left; } } } rb_link_node(node, parent, p); rb_insert_color(node, root); return 0; } /* * searches the tree for the given offset. * * fuzzy - If this is set, then we are trying to make an allocation, and we just * want a section that has at least bytes size and comes at or after the given * offset. */ static struct btrfs_free_space * tree_search_offset(struct btrfs_free_space_ctl *ctl, u64 offset, int bitmap_only, int fuzzy) { struct rb_node *n = ctl->free_space_offset.rb_node; struct btrfs_free_space *entry, *prev = NULL; u32 sectorsize = ctl->sectorsize; /* find entry that is closest to the 'offset' */ while (1) { if (!n) { entry = NULL; break; } entry = rb_entry(n, struct btrfs_free_space, offset_index); prev = entry; if (offset < entry->offset) n = n->rb_left; else if (offset > entry->offset) n = n->rb_right; else break; } if (bitmap_only) { if (!entry) return NULL; if (entry->bitmap) return entry; /* * bitmap entry and extent entry may share same offset, * in that case, bitmap entry comes after extent entry. */ n = rb_next(n); if (!n) return NULL; entry = rb_entry(n, struct btrfs_free_space, offset_index); if (entry->offset != offset) return NULL; WARN_ON(!entry->bitmap); return entry; } else if (entry) { if (entry->bitmap) { /* * if previous extent entry covers the offset, * we should return it instead of the bitmap entry */ n = rb_prev(&entry->offset_index); if (n) { prev = rb_entry(n, struct btrfs_free_space, offset_index); if (!prev->bitmap && prev->offset + prev->bytes > offset) entry = prev; } } return entry; } if (!prev) return NULL; /* find last entry before the 'offset' */ entry = prev; if (entry->offset > offset) { n = rb_prev(&entry->offset_index); if (n) { entry = rb_entry(n, struct btrfs_free_space, offset_index); BUG_ON(entry->offset > offset); } else { if (fuzzy) return entry; else return NULL; } } if (entry->bitmap) { n = rb_prev(&entry->offset_index); if (n) { prev = rb_entry(n, struct btrfs_free_space, offset_index); if (!prev->bitmap && prev->offset + prev->bytes > offset) return prev; } if (entry->offset + BITS_PER_BITMAP(sectorsize) * ctl->unit > offset) return entry; } else if (entry->offset + entry->bytes > offset) return entry; if (!fuzzy) return NULL; while (1) { if (entry->bitmap) { if (entry->offset + BITS_PER_BITMAP(sectorsize) * ctl->unit > offset) break; } else { if (entry->offset + entry->bytes > offset) break; } n = rb_next(&entry->offset_index); if (!n) return NULL; entry = rb_entry(n, struct btrfs_free_space, offset_index); } return entry; } void unlink_free_space(struct btrfs_free_space_ctl *ctl, struct btrfs_free_space *info) { rb_erase(&info->offset_index, &ctl->free_space_offset); ctl->free_extents--; ctl->free_space -= info->bytes; } static int link_free_space(struct btrfs_free_space_ctl *ctl, struct btrfs_free_space *info) { int ret = 0; BUG_ON(!info->bitmap && !info->bytes); ret = tree_insert_offset(&ctl->free_space_offset, info->offset, &info->offset_index, (info->bitmap != NULL)); if (ret) return ret; ctl->free_space += info->bytes; ctl->free_extents++; return ret; } static int search_bitmap(struct btrfs_free_space_ctl *ctl, struct btrfs_free_space *bitmap_info, u64 *offset, u64 *bytes) { unsigned long found_bits = 0; unsigned long bits, i; unsigned long next_zero; u32 sectorsize = ctl->sectorsize; i = offset_to_bit(bitmap_info->offset, ctl->unit, max_t(u64, *offset, bitmap_info->offset)); bits = bytes_to_bits(*bytes, ctl->unit); for_each_set_bit_from(i, bitmap_info->bitmap, BITS_PER_BITMAP(sectorsize)) { next_zero = find_next_zero_bit(bitmap_info->bitmap, BITS_PER_BITMAP(sectorsize), i); if ((next_zero - i) >= bits) { found_bits = next_zero - i; break; } i = next_zero; } if (found_bits) { *offset = (u64)(i * ctl->unit) + bitmap_info->offset; *bytes = (u64)(found_bits) * ctl->unit; return 0; } return -1; } struct btrfs_free_space * btrfs_find_free_space(struct btrfs_free_space_ctl *ctl, u64 offset, u64 bytes) { return tree_search_offset(ctl, offset, 0, 0); } static void try_merge_free_space(struct btrfs_free_space_ctl *ctl, struct btrfs_free_space *info) { struct btrfs_free_space *left_info; struct btrfs_free_space *right_info; u64 offset = info->offset; u64 bytes = info->bytes; /* * first we want to see if there is free space adjacent to the range we * are adding, if there is remove that struct and add a new one to * cover the entire range */ right_info = tree_search_offset(ctl, offset + bytes, 0, 0); if (right_info && rb_prev(&right_info->offset_index)) left_info = rb_entry(rb_prev(&right_info->offset_index), struct btrfs_free_space, offset_index); else left_info = tree_search_offset(ctl, offset - 1, 0, 0); if (right_info && !right_info->bitmap) { unlink_free_space(ctl, right_info); info->bytes += right_info->bytes; free(right_info); } if (left_info && !left_info->bitmap && left_info->offset + left_info->bytes == offset) { unlink_free_space(ctl, left_info); info->offset = left_info->offset; info->bytes += left_info->bytes; free(left_info); } } void btrfs_dump_free_space(struct btrfs_block_group_cache *block_group, u64 bytes) { struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl; struct btrfs_free_space *info; struct rb_node *n; int count = 0; for (n = rb_first(&ctl->free_space_offset); n; n = rb_next(n)) { info = rb_entry(n, struct btrfs_free_space, offset_index); if (info->bytes >= bytes && !block_group->ro) count++; printk("entry offset %llu, bytes %llu, bitmap %s\n", (unsigned long long)info->offset, (unsigned long long)info->bytes, (info->bitmap) ? "yes" : "no"); } printk("%d blocks of free space at or bigger than bytes is \n", count); } int btrfs_init_free_space_ctl(struct btrfs_block_group_cache *block_group, int sectorsize) { struct btrfs_free_space_ctl *ctl; ctl = calloc(1, sizeof(*ctl)); if (!ctl) return -ENOMEM; ctl->sectorsize = sectorsize; ctl->unit = sectorsize; ctl->start = block_group->key.objectid; ctl->private = block_group; block_group->free_space_ctl = ctl; return 0; } void __btrfs_remove_free_space_cache(struct btrfs_free_space_ctl *ctl) { struct btrfs_free_space *info; struct rb_node *node; while ((node = rb_last(&ctl->free_space_offset)) != NULL) { info = rb_entry(node, struct btrfs_free_space, offset_index); unlink_free_space(ctl, info); free(info->bitmap); free(info); } } void btrfs_remove_free_space_cache(struct btrfs_block_group_cache *block_group) { __btrfs_remove_free_space_cache(block_group->free_space_ctl); } static int btrfs_add_free_space(struct btrfs_free_space_ctl *ctl, u64 offset, u64 bytes) { struct btrfs_free_space *info; int ret = 0; info = calloc(1, sizeof(*info)); if (!info) return -ENOMEM; info->offset = offset; info->bytes = bytes; try_merge_free_space(ctl, info); ret = link_free_space(ctl, info); if (ret) { printk(KERN_CRIT "btrfs: unable to add free space :%d\n", ret); BUG_ON(ret == -EEXIST); } return ret; } /* * Merges all the free space cache and kills the bitmap entries since we just * want to use the free space cache to verify it's correct, no reason to keep * the bitmaps around to confuse things. */ static void merge_space_tree(struct btrfs_free_space_ctl *ctl) { struct btrfs_free_space *e, *prev = NULL; struct rb_node *n; int ret; u32 sectorsize = ctl->sectorsize; again: prev = NULL; for (n = rb_first(&ctl->free_space_offset); n; n = rb_next(n)) { e = rb_entry(n, struct btrfs_free_space, offset_index); if (e->bitmap) { u64 offset = e->offset, bytes = ctl->unit; u64 end; end = e->offset + (u64)(BITS_PER_BITMAP(sectorsize) * ctl->unit); unlink_free_space(ctl, e); while (!(search_bitmap(ctl, e, &offset, &bytes))) { ret = btrfs_add_free_space(ctl, offset, bytes); BUG_ON(ret); offset += bytes; if (offset >= end) break; bytes = ctl->unit; } free(e->bitmap); free(e); goto again; } if (!prev) goto next; if (prev->offset + prev->bytes == e->offset) { unlink_free_space(ctl, prev); unlink_free_space(ctl, e); prev->bytes += e->bytes; free(e); link_free_space(ctl, prev); goto again; } next: prev = e; } } partclone-0.2.86/src/btrfs/free-space-cache.h000066400000000000000000000033701262102574200207350ustar00rootroot00000000000000/* * Copyright (C) 2009 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. */ #ifndef __BTRFS_FREE_SPACE_CACHE #define __BTRFS_FREE_SPACE_CACHE struct btrfs_free_space { struct rb_node offset_index; u64 offset; u64 bytes; unsigned long *bitmap; struct list_head list; }; struct btrfs_free_space_ctl { struct rb_root free_space_offset; u64 free_space; int extents_thresh; int free_extents; int total_bitmaps; int unit; u64 start; void *private; u32 sectorsize; }; int load_free_space_cache(struct btrfs_fs_info *fs_info, struct btrfs_block_group_cache *block_group); void __btrfs_remove_free_space_cache(struct btrfs_free_space_ctl *ctl); void btrfs_remove_free_space_cache(struct btrfs_block_group_cache *block_group); void btrfs_dump_free_space(struct btrfs_block_group_cache *block_group, u64 bytes); struct btrfs_free_space * btrfs_find_free_space(struct btrfs_free_space_ctl *ctl, u64 offset, u64 bytes); int btrfs_init_free_space_ctl(struct btrfs_block_group_cache *block_group, int sectorsize); void unlink_free_space(struct btrfs_free_space_ctl *ctl, struct btrfs_free_space *info); #endif partclone-0.2.86/src/btrfs/hash.h000066400000000000000000000015501262102574200166030ustar00rootroot00000000000000/* * Copyright (C) 2007 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. */ #ifndef __HASH__ #define __HASH__ #include "crc32c.h" static inline u64 btrfs_name_hash(const char *name, int len) { return crc32c((u32)~1, name, len); } #endif partclone-0.2.86/src/btrfs/inode-item.c000066400000000000000000000102521262102574200177040ustar00rootroot00000000000000/* * Copyright (C) 2007 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. */ #include "ctree.h" #include "disk-io.h" #include "transaction.h" static int find_name_in_backref(struct btrfs_path *path, const char * name, int name_len, struct btrfs_inode_ref **ref_ret) { struct extent_buffer *leaf; struct btrfs_inode_ref *ref; unsigned long ptr; unsigned long name_ptr; u32 item_size; u32 cur_offset = 0; int len; leaf = path->nodes[0]; item_size = btrfs_item_size_nr(leaf, path->slots[0]); ptr = btrfs_item_ptr_offset(leaf, path->slots[0]); while (cur_offset < item_size) { ref = (struct btrfs_inode_ref *)(ptr + cur_offset); len = btrfs_inode_ref_name_len(leaf, ref); name_ptr = (unsigned long)(ref + 1); cur_offset += len + sizeof(*ref); if (len != name_len) continue; if (memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0) { *ref_ret = ref; return 1; } } return 0; } int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, const char *name, int name_len, u64 inode_objectid, u64 ref_objectid, u64 index) { struct btrfs_path *path; struct btrfs_key key; struct btrfs_inode_ref *ref; unsigned long ptr; int ret; int ins_len = name_len + sizeof(*ref); key.objectid = inode_objectid; key.offset = ref_objectid; btrfs_set_key_type(&key, BTRFS_INODE_REF_KEY); path = btrfs_alloc_path(); if (!path) return -ENOMEM; ret = btrfs_insert_empty_item(trans, root, path, &key, ins_len); if (ret == -EEXIST) { u32 old_size; if (find_name_in_backref(path, name, name_len, &ref)) goto out; old_size = btrfs_item_size_nr(path->nodes[0], path->slots[0]); ret = btrfs_extend_item(trans, root, path, ins_len); BUG_ON(ret); ref = btrfs_item_ptr(path->nodes[0], path->slots[0], struct btrfs_inode_ref); ref = (struct btrfs_inode_ref *)((unsigned long)ref + old_size); btrfs_set_inode_ref_name_len(path->nodes[0], ref, name_len); btrfs_set_inode_ref_index(path->nodes[0], ref, index); ptr = (unsigned long)(ref + 1); ret = 0; } else if (ret < 0) { goto out; } else { ref = btrfs_item_ptr(path->nodes[0], path->slots[0], struct btrfs_inode_ref); btrfs_set_inode_ref_name_len(path->nodes[0], ref, name_len); btrfs_set_inode_ref_index(path->nodes[0], ref, index); ptr = (unsigned long)(ref + 1); } write_extent_buffer(path->nodes[0], name, ptr, name_len); btrfs_mark_buffer_dirty(path->nodes[0]); out: btrfs_free_path(path); return ret; } int btrfs_lookup_inode(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, struct btrfs_key *location, int mod) { int ins_len = mod < 0 ? -1 : 0; int cow = mod != 0; int ret; int slot; struct extent_buffer *leaf; struct btrfs_key found_key; ret = btrfs_search_slot(trans, root, location, path, ins_len, cow); if (ret > 0 && btrfs_key_type(location) == BTRFS_ROOT_ITEM_KEY && location->offset == (u64)-1 && path->slots[0] != 0) { slot = path->slots[0] - 1; leaf = path->nodes[0]; btrfs_item_key_to_cpu(leaf, &found_key, slot); if (found_key.objectid == location->objectid && btrfs_key_type(&found_key) == btrfs_key_type(location)) { path->slots[0]--; return 0; } } return ret; } int btrfs_insert_inode(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 objectid, struct btrfs_inode_item *inode_item) { int ret; struct btrfs_key key; key.objectid = objectid; key.type = BTRFS_INODE_ITEM_KEY; key.offset = 0; ret = btrfs_insert_item(trans, root, &key, inode_item, sizeof(*inode_item)); return ret; } partclone-0.2.86/src/btrfs/inode-map.c000066400000000000000000000046501262102574200175300ustar00rootroot00000000000000/* * Copyright (C) 2007 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. */ #include "ctree.h" #include "disk-io.h" #include "transaction.h" /* * walks the btree of allocated inodes and find a hole. */ int btrfs_find_free_objectid(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 dirid, u64 *objectid) { struct btrfs_path *path; struct btrfs_key key; int ret; int slot = 0; u64 last_ino = 0; int start_found; struct extent_buffer *l; struct btrfs_key search_key; u64 search_start = dirid; path = btrfs_alloc_path(); BUG_ON(!path); search_start = root->last_inode_alloc; search_start = max((unsigned long long)search_start, BTRFS_FIRST_FREE_OBJECTID); search_key.objectid = search_start; search_key.offset = 0; btrfs_init_path(path); start_found = 0; ret = btrfs_search_slot(trans, root, &search_key, path, 0, 0); if (ret < 0) goto error; if (path->slots[0] > 0) path->slots[0]--; while (1) { l = path->nodes[0]; slot = path->slots[0]; if (slot >= btrfs_header_nritems(l)) { ret = btrfs_next_leaf(root, path); if (ret == 0) continue; if (ret < 0) goto error; if (!start_found) { *objectid = search_start; start_found = 1; goto found; } *objectid = last_ino > search_start ? last_ino : search_start; goto found; } btrfs_item_key_to_cpu(l, &key, slot); if (key.objectid >= search_start) { if (start_found) { if (last_ino < search_start) last_ino = search_start; if (key.objectid > last_ino) { *objectid = last_ino; goto found; } } } start_found = 1; last_ino = key.objectid + 1; path->slots[0]++; } // FIXME -ENOSPC found: root->last_inode_alloc = *objectid; btrfs_free_path(path); BUG_ON(*objectid < search_start); return 0; error: btrfs_free_path(path); return ret; } partclone-0.2.86/src/btrfs/ioctl.h000066400000000000000000000433561262102574200170040ustar00rootroot00000000000000/* * Copyright (C) 2007 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. */ #ifndef __IOCTL_ #define __IOCTL_ #include #include #include #ifdef __cplusplus extern "C" { #endif #define BTRFS_IOCTL_MAGIC 0x94 #define BTRFS_VOL_NAME_MAX 255 /* this should be 4k */ #define BTRFS_PATH_NAME_MAX 4087 struct btrfs_ioctl_vol_args { __s64 fd; char name[BTRFS_PATH_NAME_MAX + 1]; }; #define BTRFS_DEVICE_PATH_NAME_MAX 1024 #define BTRFS_SUBVOL_CREATE_ASYNC (1ULL << 0) #define BTRFS_SUBVOL_RDONLY (1ULL << 1) #define BTRFS_SUBVOL_QGROUP_INHERIT (1ULL << 2) #define BTRFS_QGROUP_INHERIT_SET_LIMITS (1ULL << 0) struct btrfs_qgroup_limit { __u64 flags; __u64 max_referenced; __u64 max_exclusive; __u64 rsv_referenced; __u64 rsv_exclusive; }; struct btrfs_qgroup_inherit { __u64 flags; __u64 num_qgroups; __u64 num_ref_copies; __u64 num_excl_copies; struct btrfs_qgroup_limit lim; __u64 qgroups[0]; }; struct btrfs_ioctl_qgroup_limit_args { __u64 qgroupid; struct btrfs_qgroup_limit lim; }; #define BTRFS_SUBVOL_NAME_MAX 4039 struct btrfs_ioctl_vol_args_v2 { __s64 fd; __u64 transid; __u64 flags; union { struct { __u64 size; struct btrfs_qgroup_inherit *qgroup_inherit; }; __u64 unused[4]; }; char name[BTRFS_SUBVOL_NAME_MAX + 1]; }; #define BTRFS_FSID_SIZE 16 #define BTRFS_UUID_SIZE 16 struct btrfs_scrub_progress { __u64 data_extents_scrubbed; __u64 tree_extents_scrubbed; __u64 data_bytes_scrubbed; __u64 tree_bytes_scrubbed; __u64 read_errors; __u64 csum_errors; __u64 verify_errors; __u64 no_csum; __u64 csum_discards; __u64 super_errors; __u64 malloc_errors; __u64 uncorrectable_errors; __u64 corrected_errors; __u64 last_physical; __u64 unverified_errors; }; #define BTRFS_SCRUB_READONLY 1 struct btrfs_ioctl_scrub_args { __u64 devid; /* in */ __u64 start; /* in */ __u64 end; /* in */ __u64 flags; /* in */ struct btrfs_scrub_progress progress; /* out */ /* pad to 1k */ __u64 unused[(1024-32-sizeof(struct btrfs_scrub_progress))/8]; }; #define BTRFS_IOCTL_DEV_REPLACE_CONT_READING_FROM_SRCDEV_MODE_ALWAYS 0 #define BTRFS_IOCTL_DEV_REPLACE_CONT_READING_FROM_SRCDEV_MODE_AVOID 1 struct btrfs_ioctl_dev_replace_start_params { __u64 srcdevid; /* in, if 0, use srcdev_name instead */ __u64 cont_reading_from_srcdev_mode; /* in, see #define * above */ __u8 srcdev_name[BTRFS_DEVICE_PATH_NAME_MAX + 1]; /* in */ __u8 tgtdev_name[BTRFS_DEVICE_PATH_NAME_MAX + 1]; /* in */ }; #define BTRFS_IOCTL_DEV_REPLACE_STATE_NEVER_STARTED 0 #define BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED 1 #define BTRFS_IOCTL_DEV_REPLACE_STATE_FINISHED 2 #define BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED 3 #define BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED 4 struct btrfs_ioctl_dev_replace_status_params { __u64 replace_state; /* out, see #define above */ __u64 progress_1000; /* out, 0 <= x <= 1000 */ __u64 time_started; /* out, seconds since 1-Jan-1970 */ __u64 time_stopped; /* out, seconds since 1-Jan-1970 */ __u64 num_write_errors; /* out */ __u64 num_uncorrectable_read_errors; /* out */ }; #define BTRFS_IOCTL_DEV_REPLACE_CMD_START 0 #define BTRFS_IOCTL_DEV_REPLACE_CMD_STATUS 1 #define BTRFS_IOCTL_DEV_REPLACE_CMD_CANCEL 2 #define BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_RESULT -1 #define BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_ERROR 0 #define BTRFS_IOCTL_DEV_REPLACE_RESULT_NOT_STARTED 1 #define BTRFS_IOCTL_DEV_REPLACE_RESULT_ALREADY_STARTED 2 #define BTRFS_IOCTL_DEV_REPLACE_RESULT_SCRUB_INPROGRESS 3 struct btrfs_ioctl_dev_replace_args { __u64 cmd; /* in */ __u64 result; /* out */ union { struct btrfs_ioctl_dev_replace_start_params start; struct btrfs_ioctl_dev_replace_status_params status; }; /* in/out */ __u64 spare[64]; }; struct btrfs_ioctl_dev_info_args { __u64 devid; /* in/out */ __u8 uuid[BTRFS_UUID_SIZE]; /* in/out */ __u64 bytes_used; /* out */ __u64 total_bytes; /* out */ __u64 unused[379]; /* pad to 4k */ __u8 path[BTRFS_DEVICE_PATH_NAME_MAX]; /* out */ }; struct btrfs_ioctl_fs_info_args { __u64 max_id; /* out */ __u64 num_devices; /* out */ __u8 fsid[BTRFS_FSID_SIZE]; /* out */ __u64 reserved[124]; /* pad to 1k */ }; /* balance control ioctl modes */ #define BTRFS_BALANCE_CTL_PAUSE 1 #define BTRFS_BALANCE_CTL_CANCEL 2 #define BTRFS_BALANCE_CTL_RESUME 3 /* * this is packed, because it should be exactly the same as its disk * byte order counterpart (struct btrfs_disk_balance_args) */ struct btrfs_balance_args { __u64 profiles; __u64 usage; __u64 devid; __u64 pstart; __u64 pend; __u64 vstart; __u64 vend; __u64 target; __u64 flags; __u64 limit; __u64 unused[7]; } __attribute__ ((__packed__)); struct btrfs_balance_progress { __u64 expected; __u64 considered; __u64 completed; }; #define BTRFS_BALANCE_STATE_RUNNING (1ULL << 0) #define BTRFS_BALANCE_STATE_PAUSE_REQ (1ULL << 1) #define BTRFS_BALANCE_STATE_CANCEL_REQ (1ULL << 2) struct btrfs_ioctl_balance_args { __u64 flags; /* in/out */ __u64 state; /* out */ struct btrfs_balance_args data; /* in/out */ struct btrfs_balance_args meta; /* in/out */ struct btrfs_balance_args sys; /* in/out */ struct btrfs_balance_progress stat; /* out */ __u64 unused[72]; /* pad to 1k */ }; struct btrfs_ioctl_search_key { /* which root are we searching. 0 is the tree of tree roots */ __u64 tree_id; /* keys returned will be >= min and <= max */ __u64 min_objectid; __u64 max_objectid; /* keys returned will be >= min and <= max */ __u64 min_offset; __u64 max_offset; /* max and min transids to search for */ __u64 min_transid; __u64 max_transid; /* keys returned will be >= min and <= max */ __u32 min_type; __u32 max_type; /* * how many items did userland ask for, and how many are we * returning */ __u32 nr_items; /* align to 64 bits */ __u32 unused; /* some extra for later */ __u64 unused1; __u64 unused2; __u64 unused3; __u64 unused4; }; struct btrfs_ioctl_search_header { __u64 transid; __u64 objectid; __u64 offset; __u32 type; __u32 len; } __attribute__((may_alias)); #define BTRFS_SEARCH_ARGS_BUFSIZE (4096 - sizeof(struct btrfs_ioctl_search_key)) /* * the buf is an array of search headers where * each header is followed by the actual item * the type field is expanded to 32 bits for alignment */ struct btrfs_ioctl_search_args { struct btrfs_ioctl_search_key key; char buf[BTRFS_SEARCH_ARGS_BUFSIZE]; }; #define BTRFS_INO_LOOKUP_PATH_MAX 4080 struct btrfs_ioctl_ino_lookup_args { __u64 treeid; __u64 objectid; char name[BTRFS_INO_LOOKUP_PATH_MAX]; }; /* flags for the defrag range ioctl */ #define BTRFS_DEFRAG_RANGE_COMPRESS 1 #define BTRFS_DEFRAG_RANGE_START_IO 2 struct btrfs_ioctl_defrag_range_args { /* start of the defrag operation */ __u64 start; /* number of bytes to defrag, use (u64)-1 to say all */ __u64 len; /* * flags for the operation, which can include turning * on compression for this one defrag */ __u64 flags; /* * any extent bigger than this will be considered * already defragged. Use 0 to take the kernel default * Use 1 to say every single extent must be rewritten */ __u32 extent_thresh; /* * which compression method to use if turning on compression * for this defrag operation. If unspecified, zlib will * be used */ __u32 compress_type; /* spare for later */ __u32 unused[4]; }; struct btrfs_ioctl_space_info { __u64 flags; __u64 total_bytes; __u64 used_bytes; }; struct btrfs_ioctl_space_args { __u64 space_slots; __u64 total_spaces; struct btrfs_ioctl_space_info spaces[0]; }; struct btrfs_data_container { __u32 bytes_left; /* out -- bytes not needed to deliver output */ __u32 bytes_missing; /* out -- additional bytes needed for result */ __u32 elem_cnt; /* out */ __u32 elem_missed; /* out */ __u64 val[0]; /* out */ }; struct btrfs_ioctl_ino_path_args { __u64 inum; /* in */ __u64 size; /* in */ __u64 reserved[4]; /* struct btrfs_data_container *fspath; out */ __u64 fspath; /* out */ }; struct btrfs_ioctl_logical_ino_args { __u64 logical; /* in */ __u64 size; /* in */ __u64 reserved[4]; /* struct btrfs_data_container *inodes; out */ __u64 inodes; }; struct btrfs_ioctl_timespec { __u64 sec; __u32 nsec; }; struct btrfs_ioctl_received_subvol_args { char uuid[BTRFS_UUID_SIZE]; /* in */ __u64 stransid; /* in */ __u64 rtransid; /* out */ struct btrfs_ioctl_timespec stime; /* in */ struct btrfs_ioctl_timespec rtime; /* out */ __u64 flags; /* in */ __u64 reserved[16]; /* in */ }; /* * Caller doesn't want file data in the send stream, even if the * search of clone sources doesn't find an extent. UPDATE_EXTENT * commands will be sent instead of WRITE commands. */ #define BTRFS_SEND_FLAG_NO_FILE_DATA 0x1 /* * Do not add the leading stream header. Used when multiple snapshots * are sent back to back. */ #define BTRFS_SEND_FLAG_OMIT_STREAM_HEADER 0x2 /* * Omit the command at the end of the stream that indicated the end * of the stream. This option is used when multiple snapshots are * sent back to back. */ #define BTRFS_SEND_FLAG_OMIT_END_CMD 0x4 struct btrfs_ioctl_send_args { __s64 send_fd; /* in */ __u64 clone_sources_count; /* in */ __u64 *clone_sources; /* in */ __u64 parent_root; /* in */ __u64 flags; /* in */ __u64 reserved[4]; /* in */ }; enum btrfs_dev_stat_values { /* disk I/O failure stats */ BTRFS_DEV_STAT_WRITE_ERRS, /* EIO or EREMOTEIO from lower layers */ BTRFS_DEV_STAT_READ_ERRS, /* EIO or EREMOTEIO from lower layers */ BTRFS_DEV_STAT_FLUSH_ERRS, /* EIO or EREMOTEIO from lower layers */ /* stats for indirect indications for I/O failures */ BTRFS_DEV_STAT_CORRUPTION_ERRS, /* checksum error, bytenr error or * contents is illegal: this is an * indication that the block was damaged * during read or write, or written to * wrong location or read from wrong * location */ BTRFS_DEV_STAT_GENERATION_ERRS, /* an indication that blocks have not * been written */ BTRFS_DEV_STAT_VALUES_MAX }; /* Reset statistics after reading; needs SYS_ADMIN capability */ #define BTRFS_DEV_STATS_RESET (1ULL << 0) struct btrfs_ioctl_get_dev_stats { __u64 devid; /* in */ __u64 nr_items; /* in/out */ __u64 flags; /* in/out */ /* out values: */ __u64 values[BTRFS_DEV_STAT_VALUES_MAX]; __u64 unused[128 - 2 - BTRFS_DEV_STAT_VALUES_MAX]; /* pad to 1k */ }; /* BTRFS_IOC_SNAP_CREATE is no longer used by the btrfs command */ #define BTRFS_QUOTA_CTL_ENABLE 1 #define BTRFS_QUOTA_CTL_DISABLE 2 /* 3 has formerly been reserved for BTRFS_QUOTA_CTL_RESCAN */ struct btrfs_ioctl_quota_ctl_args { __u64 cmd; __u64 status; }; struct btrfs_ioctl_quota_rescan_args { __u64 flags; __u64 progress; __u64 reserved[6]; }; struct btrfs_ioctl_qgroup_assign_args { __u64 assign; __u64 src; __u64 dst; }; struct btrfs_ioctl_qgroup_create_args { __u64 create; __u64 qgroupid; }; /* Error codes as returned by the kernel */ enum btrfs_err_code { notused, BTRFS_ERROR_DEV_RAID1_MIN_NOT_MET, BTRFS_ERROR_DEV_RAID10_MIN_NOT_MET, BTRFS_ERROR_DEV_RAID5_MIN_NOT_MET, BTRFS_ERROR_DEV_RAID6_MIN_NOT_MET, BTRFS_ERROR_DEV_TGT_REPLACE, BTRFS_ERROR_DEV_MISSING_NOT_FOUND, BTRFS_ERROR_DEV_ONLY_WRITABLE, BTRFS_ERROR_DEV_EXCL_RUN_IN_PROGRESS }; /* An error code to error string mapping for the kernel * error codes */ static inline char *btrfs_err_str(enum btrfs_err_code err_code) { switch (err_code) { case BTRFS_ERROR_DEV_RAID1_MIN_NOT_MET: return "unable to go below two devices on raid1"; case BTRFS_ERROR_DEV_RAID10_MIN_NOT_MET: return "unable to go below four devices on raid10"; case BTRFS_ERROR_DEV_RAID5_MIN_NOT_MET: return "unable to go below two devices on raid5"; case BTRFS_ERROR_DEV_RAID6_MIN_NOT_MET: return "unable to go below three devices on raid6"; case BTRFS_ERROR_DEV_TGT_REPLACE: return "unable to remove the dev_replace target dev"; case BTRFS_ERROR_DEV_MISSING_NOT_FOUND: return "no missing devices found to remove"; case BTRFS_ERROR_DEV_ONLY_WRITABLE: return "unable to remove the only writeable device"; case BTRFS_ERROR_DEV_EXCL_RUN_IN_PROGRESS: return "add/delete/balance/replace/resize operation " "in progress"; default: return NULL; } } #define BTRFS_IOC_SNAP_CREATE _IOW(BTRFS_IOCTL_MAGIC, 1, \ struct btrfs_ioctl_vol_args) #define BTRFS_IOC_DEFRAG _IOW(BTRFS_IOCTL_MAGIC, 2, \ struct btrfs_ioctl_vol_args) #define BTRFS_IOC_RESIZE _IOW(BTRFS_IOCTL_MAGIC, 3, \ struct btrfs_ioctl_vol_args) #define BTRFS_IOC_SCAN_DEV _IOW(BTRFS_IOCTL_MAGIC, 4, \ struct btrfs_ioctl_vol_args) /* With a @src_length of zero, the range from @src_offset->EOF is cloned! */ struct btrfs_ioctl_clone_range_args { __s64 src_fd; __u64 src_offset, src_length; __u64 dest_offset; }; /* trans start and trans end are dangerous, and only for * use by applications that know how to avoid the * resulting deadlocks */ #define BTRFS_IOC_TRANS_START _IO(BTRFS_IOCTL_MAGIC, 6) #define BTRFS_IOC_TRANS_END _IO(BTRFS_IOCTL_MAGIC, 7) #define BTRFS_IOC_SYNC _IO(BTRFS_IOCTL_MAGIC, 8) #define BTRFS_IOC_CLONE _IOW(BTRFS_IOCTL_MAGIC, 9, int) #define BTRFS_IOC_ADD_DEV _IOW(BTRFS_IOCTL_MAGIC, 10, \ struct btrfs_ioctl_vol_args) #define BTRFS_IOC_RM_DEV _IOW(BTRFS_IOCTL_MAGIC, 11, \ struct btrfs_ioctl_vol_args) #define BTRFS_IOC_BALANCE _IOW(BTRFS_IOCTL_MAGIC, 12, \ struct btrfs_ioctl_vol_args) #define BTRFS_IOC_CLONE_RANGE _IOW(BTRFS_IOCTL_MAGIC, 13, \ struct btrfs_ioctl_clone_range_args) #define BTRFS_IOC_SUBVOL_CREATE _IOW(BTRFS_IOCTL_MAGIC, 14, \ struct btrfs_ioctl_vol_args) #define BTRFS_IOC_SNAP_DESTROY _IOW(BTRFS_IOCTL_MAGIC, 15, \ struct btrfs_ioctl_vol_args) #define BTRFS_IOC_DEFRAG_RANGE _IOW(BTRFS_IOCTL_MAGIC, 16, \ struct btrfs_ioctl_defrag_range_args) #define BTRFS_IOC_TREE_SEARCH _IOWR(BTRFS_IOCTL_MAGIC, 17, \ struct btrfs_ioctl_search_args) #define BTRFS_IOC_INO_LOOKUP _IOWR(BTRFS_IOCTL_MAGIC, 18, \ struct btrfs_ioctl_ino_lookup_args) #define BTRFS_IOC_DEFAULT_SUBVOL _IOW(BTRFS_IOCTL_MAGIC, 19, __u64) #define BTRFS_IOC_SPACE_INFO _IOWR(BTRFS_IOCTL_MAGIC, 20, \ struct btrfs_ioctl_space_args) #define BTRFS_IOC_START_SYNC _IOR(BTRFS_IOCTL_MAGIC, 24, __u64) #define BTRFS_IOC_WAIT_SYNC _IOW(BTRFS_IOCTL_MAGIC, 22, __u64) #define BTRFS_IOC_SNAP_CREATE_V2 _IOW(BTRFS_IOCTL_MAGIC, 23, \ struct btrfs_ioctl_vol_args_v2) #define BTRFS_IOC_SUBVOL_CREATE_V2 _IOW(BTRFS_IOCTL_MAGIC, 24, \ struct btrfs_ioctl_vol_args_v2) #define BTRFS_IOC_SUBVOL_GETFLAGS _IOR(BTRFS_IOCTL_MAGIC, 25, __u64) #define BTRFS_IOC_SUBVOL_SETFLAGS _IOW(BTRFS_IOCTL_MAGIC, 26, __u64) #define BTRFS_IOC_SCRUB _IOWR(BTRFS_IOCTL_MAGIC, 27, \ struct btrfs_ioctl_scrub_args) #define BTRFS_IOC_SCRUB_CANCEL _IO(BTRFS_IOCTL_MAGIC, 28) #define BTRFS_IOC_SCRUB_PROGRESS _IOWR(BTRFS_IOCTL_MAGIC, 29, \ struct btrfs_ioctl_scrub_args) #define BTRFS_IOC_DEV_INFO _IOWR(BTRFS_IOCTL_MAGIC, 30, \ struct btrfs_ioctl_dev_info_args) #define BTRFS_IOC_FS_INFO _IOR(BTRFS_IOCTL_MAGIC, 31, \ struct btrfs_ioctl_fs_info_args) #define BTRFS_IOC_BALANCE_V2 _IOWR(BTRFS_IOCTL_MAGIC, 32, \ struct btrfs_ioctl_balance_args) #define BTRFS_IOC_BALANCE_CTL _IOW(BTRFS_IOCTL_MAGIC, 33, int) #define BTRFS_IOC_BALANCE_PROGRESS _IOR(BTRFS_IOCTL_MAGIC, 34, \ struct btrfs_ioctl_balance_args) #define BTRFS_IOC_INO_PATHS _IOWR(BTRFS_IOCTL_MAGIC, 35, \ struct btrfs_ioctl_ino_path_args) #define BTRFS_IOC_LOGICAL_INO _IOWR(BTRFS_IOCTL_MAGIC, 36, \ struct btrfs_ioctl_ino_path_args) #define BTRFS_IOC_DEVICES_READY _IOR(BTRFS_IOCTL_MAGIC, 39, \ struct btrfs_ioctl_vol_args) #define BTRFS_IOC_SET_RECEIVED_SUBVOL _IOWR(BTRFS_IOCTL_MAGIC, 37, \ struct btrfs_ioctl_received_subvol_args) #define BTRFS_IOC_SEND _IOW(BTRFS_IOCTL_MAGIC, 38, struct btrfs_ioctl_send_args) #define BTRFS_IOC_QUOTA_CTL _IOWR(BTRFS_IOCTL_MAGIC, 40, \ struct btrfs_ioctl_quota_ctl_args) #define BTRFS_IOC_QGROUP_ASSIGN _IOW(BTRFS_IOCTL_MAGIC, 41, \ struct btrfs_ioctl_qgroup_assign_args) #define BTRFS_IOC_QGROUP_CREATE _IOW(BTRFS_IOCTL_MAGIC, 42, \ struct btrfs_ioctl_qgroup_create_args) #define BTRFS_IOC_QGROUP_LIMIT _IOR(BTRFS_IOCTL_MAGIC, 43, \ struct btrfs_ioctl_qgroup_limit_args) #define BTRFS_IOC_QUOTA_RESCAN _IOW(BTRFS_IOCTL_MAGIC, 44, \ struct btrfs_ioctl_quota_rescan_args) #define BTRFS_IOC_QUOTA_RESCAN_STATUS _IOR(BTRFS_IOCTL_MAGIC, 45, \ struct btrfs_ioctl_quota_rescan_args) #define BTRFS_IOC_QUOTA_RESCAN_WAIT _IO(BTRFS_IOCTL_MAGIC, 46) #define BTRFS_IOC_GET_FSLABEL _IOR(BTRFS_IOCTL_MAGIC, 49, \ char[BTRFS_LABEL_SIZE]) #define BTRFS_IOC_SET_FSLABEL _IOW(BTRFS_IOCTL_MAGIC, 50, \ char[BTRFS_LABEL_SIZE]) #define BTRFS_IOC_GET_DEV_STATS _IOWR(BTRFS_IOCTL_MAGIC, 52, \ struct btrfs_ioctl_get_dev_stats) #define BTRFS_IOC_DEV_REPLACE _IOWR(BTRFS_IOCTL_MAGIC, 53, \ struct btrfs_ioctl_dev_replace_args) #define BTRFS_IOC_GET_FEATURES _IOR(BTRFS_IOCTL_MAGIC, 57, \ struct btrfs_ioctl_feature_flags) #define BTRFS_IOC_SET_FEATURES _IOW(BTRFS_IOCTL_MAGIC, 57, \ struct btrfs_ioctl_feature_flags[2]) #define BTRFS_IOC_GET_SUPPORTED_FEATURES _IOR(BTRFS_IOCTL_MAGIC, 57, \ struct btrfs_ioctl_feature_flags[3]) #ifdef __cplusplus } #endif #endif partclone-0.2.86/src/btrfs/kerncompat.h000066400000000000000000000213741262102574200200310ustar00rootroot00000000000000/* * Copyright (C) 2007 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. */ #ifndef __KERNCOMPAT #define __KERNCOMPAT #include #include #include #include #include #include #include #include #include #include #ifndef BTRFS_DISABLE_BACKTRACE #include #endif #define ptr_to_u64(x) ((u64)(uintptr_t)x) #define u64_to_ptr(x) ((void *)(uintptr_t)x) #ifndef READ #define READ 0 #define WRITE 1 #define READA 2 #endif #define gfp_t int #define get_cpu_var(p) (p) #define __get_cpu_var(p) (p) #define BITS_PER_LONG (__SIZEOF_LONG__ * 8) #define __GFP_BITS_SHIFT 20 #define __GFP_BITS_MASK ((int)((1 << __GFP_BITS_SHIFT) - 1)) #define GFP_KERNEL 0 #define GFP_NOFS 0 #define __read_mostly #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) #ifndef ULONG_MAX #define ULONG_MAX (~0UL) #endif #ifndef BTRFS_DISABLE_BACKTRACE #define MAX_BACKTRACE 16 static inline void print_trace(void) { void *array[MAX_BACKTRACE]; size_t size; size = backtrace(array, MAX_BACKTRACE); backtrace_symbols_fd(array, size, 2); } static inline void assert_trace(const char *assertion, const char *filename, const char *func, unsigned line, int val) { if (val) return; if (assertion) fprintf(stderr, "%s:%d: %s: Assertion `%s` failed.\n", filename, line, func, assertion); else fprintf(stderr, "%s:%d: %s: Assertion failed.\n", filename, line, func); print_trace(); exit(1); } #define BUG() assert_trace(NULL, __FILE__, __func__, __LINE__, 0) #else #define BUG() assert(0) #endif #ifdef __CHECKER__ #define __force __attribute__((force)) #define __bitwise__ __attribute__((bitwise)) #else #define __force #define __bitwise__ #endif #ifndef __CHECKER__ /* * Since we're using primitive definitions from kernel-space, we need to * define __KERNEL__ so that system header files know which definitions * to use. */ #define __KERNEL__ #include typedef __u32 u32; typedef __u64 u64; typedef __u16 u16; typedef __u8 u8; typedef __s64 s64; typedef __s32 s32; /* * Continuing to define __KERNEL__ breaks others parts of the code, so * we can just undefine it now that we have the correct headers... */ #undef __KERNEL__ #else typedef unsigned int u32; typedef unsigned int __u32; typedef unsigned long long u64; typedef unsigned char u8; typedef unsigned short u16; typedef long long s64; typedef int s32 #endif struct vma_shared { int prio_tree_node; }; struct vm_area_struct { unsigned long vm_pgoff; unsigned long vm_start; unsigned long vm_end; struct vma_shared shared; }; struct page { unsigned long index; }; struct mutex { unsigned long lock; }; #define mutex_init(m) \ do { \ (m)->lock = 1; \ } while (0) static inline void mutex_lock(struct mutex *m) { m->lock--; } static inline void mutex_unlock(struct mutex *m) { m->lock++; } static inline int mutex_is_locked(struct mutex *m) { return (m->lock != 1); } #define cond_resched() do { } while (0) #define preempt_enable() do { } while (0) #define preempt_disable() do { } while (0) #define BITOP_MASK(nr) (1UL << ((nr) % BITS_PER_LONG)) #define BITOP_WORD(nr) ((nr) / BITS_PER_LONG) #ifndef __attribute_const__ #define __attribute_const__ __attribute__((__const__)) #endif /** * __set_bit - Set a bit in memory * @nr: the bit to set * @addr: the address to start counting from * * Unlike set_bit(), this function is non-atomic and may be reordered. * If it's called on the same region of memory simultaneously, the effect * may be that only one operation succeeds. */ static inline void __set_bit(int nr, volatile unsigned long *addr) { unsigned long mask = BITOP_MASK(nr); unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); *p |= mask; } static inline void __clear_bit(int nr, volatile unsigned long *addr) { unsigned long mask = BITOP_MASK(nr); unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); *p &= ~mask; } /** * test_bit - Determine whether a bit is set * @nr: bit number to test * @addr: Address to start counting from */ static inline int test_bit(int nr, const volatile unsigned long *addr) { return 1UL & (addr[BITOP_WORD(nr)] >> (nr & (BITS_PER_LONG-1))); } /* * error pointer */ #define MAX_ERRNO 4095 #define IS_ERR_VALUE(x) ((x) >= (unsigned long)-MAX_ERRNO) static inline void *ERR_PTR(long error) { return (void *) error; } static inline long PTR_ERR(const void *ptr) { return (long) ptr; } static inline long IS_ERR(const void *ptr) { return IS_ERR_VALUE((unsigned long)ptr); } /* * max/min macro */ #define min(x,y) ({ \ typeof(x) _x = (x); \ typeof(y) _y = (y); \ (void) (&_x == &_y); \ _x < _y ? _x : _y; }) #define max(x,y) ({ \ typeof(x) _x = (x); \ typeof(y) _y = (y); \ (void) (&_x == &_y); \ _x > _y ? _x : _y; }) #define min_t(type,x,y) \ ({ type __x = (x); type __y = (y); __x < __y ? __x: __y; }) #define max_t(type,x,y) \ ({ type __x = (x); type __y = (y); __x > __y ? __x: __y; }) /* * This looks more complex than it should be. But we need to * get the type for the ~ right in round_down (it needs to be * as wide as the result!), and we want to evaluate the macro * arguments just once each. */ #define __round_mask(x, y) ((__typeof__(x))((y)-1)) #define round_up(x, y) ((((x)-1) | __round_mask(x, y))+1) #define round_down(x, y) ((x) & ~__round_mask(x, y)) /* * printk */ #define printk(fmt, args...) fprintf(stderr, fmt, ##args) #define KERN_CRIT "" #define KERN_ERR "" /* * kmalloc/kfree */ #define kmalloc(x, y) malloc(x) #define kzalloc(x, y) calloc(1, x) #define kstrdup(x, y) strdup(x) #define kfree(x) free(x) #define vmalloc(x) malloc(x) #define vfree(x) free(x) #ifndef BTRFS_DISABLE_BACKTRACE #define BUG_ON(c) assert_trace(#c, __FILE__, __func__, __LINE__, !(c)) #else #define BUG_ON(c) assert(!(c)) #endif #define WARN_ON(c) BUG_ON(c) #ifndef BTRFS_DISABLE_BACKTRACE #define ASSERT(c) assert_trace(#c, __FILE__, __func__, __LINE__, (c)) #else #define ASSERT(c) assert(c) #endif #define container_of(ptr, type, member) ({ \ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ (type *)( (char *)__mptr - offsetof(type,member) );}) #ifdef __CHECKER__ #define __bitwise __bitwise__ #else #define __bitwise #endif typedef u16 __bitwise __le16; typedef u16 __bitwise __be16; typedef u32 __bitwise __le32; typedef u32 __bitwise __be32; typedef u64 __bitwise __le64; typedef u64 __bitwise __be64; /* Macros to generate set/get funcs for the struct fields * assume there is a lefoo_to_cpu for every type, so lets make a simple * one for u8: */ #define le8_to_cpu(v) (v) #define cpu_to_le8(v) (v) #define __le8 u8 #if __BYTE_ORDER == __BIG_ENDIAN #define cpu_to_le64(x) ((__force __le64)(u64)(bswap_64(x))) #define le64_to_cpu(x) ((__force u64)(__le64)(bswap_64(x))) #define cpu_to_le32(x) ((__force __le32)(u32)(bswap_32(x))) #define le32_to_cpu(x) ((__force u32)(__le32)(bswap_32(x))) #define cpu_to_le16(x) ((__force __le16)(u16)(bswap_16(x))) #define le16_to_cpu(x) ((__force u16)(__le16)(bswap_16(x))) #else #define cpu_to_le64(x) ((__force __le64)(u64)(x)) #define le64_to_cpu(x) ((__force u64)(__le64)(x)) #define cpu_to_le32(x) ((__force __le32)(u32)(x)) #define le32_to_cpu(x) ((__force u32)(__le32)(x)) #define cpu_to_le16(x) ((__force __le16)(u16)(x)) #define le16_to_cpu(x) ((__force u16)(__le16)(x)) #endif struct __una_u16 { __le16 x; } __attribute__((__packed__)); struct __una_u32 { __le32 x; } __attribute__((__packed__)); struct __una_u64 { __le64 x; } __attribute__((__packed__)); #define get_unaligned_le8(p) (*((u8 *)(p))) #define put_unaligned_le8(val,p) ((*((u8 *)(p))) = (val)) #define get_unaligned_le16(p) le16_to_cpu(((const struct __una_u16 *)(p))->x) #define put_unaligned_le16(val,p) (((struct __una_u16 *)(p))->x = cpu_to_le16(val)) #define get_unaligned_le32(p) le32_to_cpu(((const struct __una_u32 *)(p))->x) #define put_unaligned_le32(val,p) (((struct __una_u32 *)(p))->x = cpu_to_le32(val)) #define get_unaligned_le64(p) le64_to_cpu(((const struct __una_u64 *)(p))->x) #define put_unaligned_le64(val,p) (((struct __una_u64 *)(p))->x = cpu_to_le64(val)) #endif #ifndef true #define true 1 #define false 0 #endif #ifndef noinline #define noinline #endif partclone-0.2.86/src/btrfs/list.h000066400000000000000000000344541262102574200166440ustar00rootroot00000000000000/* * Copyright (C) 2007 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. */ #ifndef _LINUX_LIST_H #define _LINUX_LIST_H #define LIST_POISON1 ((struct list_head *) 0x00100100) #define LIST_POISON2 ((struct list_head *) 0x00200200) /* * Simple doubly linked list implementation. * * Some of the internal functions ("__xxx") are useful when * manipulating whole lists rather than single entries, as * sometimes we already know the next/prev entries and we can * generate better code by using them directly rather than * using the generic single-entry routines. */ struct list_head { struct list_head *next, *prev; }; #define LIST_HEAD_INIT(name) { &(name), &(name) } #define LIST_HEAD(name) \ struct list_head name = LIST_HEAD_INIT(name) static inline void INIT_LIST_HEAD(struct list_head *list) { list->next = list; list->prev = list; } /* * Insert a new entry between two known consecutive entries. * * This is only for internal list manipulation where we know * the prev/next entries already! */ #ifndef CONFIG_DEBUG_LIST static inline void __list_add(struct list_head *xnew, struct list_head *prev, struct list_head *next) { next->prev = xnew; xnew->next = next; xnew->prev = prev; prev->next = xnew; } #else extern void __list_add(struct list_head *xnew, struct list_head *prev, struct list_head *next); #endif /** * list_add - add a new entry * @new: new entry to be added * @head: list head to add it after * * Insert a new entry after the specified head. * This is good for implementing stacks. */ #ifndef CONFIG_DEBUG_LIST static inline void list_add(struct list_head *xnew, struct list_head *head) { __list_add(xnew, head, head->next); } #else extern void list_add(struct list_head *xnew, struct list_head *head); #endif /** * list_add_tail - add a new entry * @new: new entry to be added * @head: list head to add it before * * Insert a new entry before the specified head. * This is useful for implementing queues. */ static inline void list_add_tail(struct list_head *xnew, struct list_head *head) { __list_add(xnew, head->prev, head); } /* * Delete a list entry by making the prev/next entries * point to each other. * * This is only for internal list manipulation where we know * the prev/next entries already! */ static inline void __list_del(struct list_head * prev, struct list_head * next) { next->prev = prev; prev->next = next; } /** * list_del - deletes entry from list. * @entry: the element to delete from the list. * Note: list_empty on entry does not return true after this, the entry is * in an undefined state. */ #ifndef CONFIG_DEBUG_LIST static inline void list_del(struct list_head *entry) { __list_del(entry->prev, entry->next); entry->next = LIST_POISON1; entry->prev = LIST_POISON2; } #else extern void list_del(struct list_head *entry); #endif /** * list_replace - replace old entry by new one * @old : the element to be replaced * @new : the new element to insert * Note: if 'old' was empty, it will be overwritten. */ static inline void list_replace(struct list_head *old, struct list_head *xnew) { xnew->next = old->next; xnew->next->prev = xnew; xnew->prev = old->prev; xnew->prev->next = xnew; } static inline void list_replace_init(struct list_head *old, struct list_head *xnew) { list_replace(old, xnew); INIT_LIST_HEAD(old); } /** * list_del_init - deletes entry from list and reinitialize it. * @entry: the element to delete from the list. */ static inline void list_del_init(struct list_head *entry) { __list_del(entry->prev, entry->next); INIT_LIST_HEAD(entry); } /** * list_move - delete from one list and add as another's head * @list: the entry to move * @head: the head that will precede our entry */ static inline void list_move(struct list_head *list, struct list_head *head) { __list_del(list->prev, list->next); list_add(list, head); } /** * list_move_tail - delete from one list and add as another's tail * @list: the entry to move * @head: the head that will follow our entry */ static inline void list_move_tail(struct list_head *list, struct list_head *head) { __list_del(list->prev, list->next); list_add_tail(list, head); } /** * list_is_last - tests whether @list is the last entry in list @head * @list: the entry to test * @head: the head of the list */ static inline int list_is_last(const struct list_head *list, const struct list_head *head) { return list->next == head; } /** * list_empty - tests whether a list is empty * @head: the list to test. */ static inline int list_empty(const struct list_head *head) { return head->next == head; } /** * list_empty_careful - tests whether a list is empty and not being modified * @head: the list to test * * Description: * tests whether a list is empty _and_ checks that no other CPU might be * in the process of modifying either member (next or prev) * * NOTE: using list_empty_careful() without synchronization * can only be safe if the only activity that can happen * to the list entry is list_del_init(). Eg. it cannot be used * if another CPU could re-list_add() it. */ static inline int list_empty_careful(const struct list_head *head) { struct list_head *next = head->next; return (next == head) && (next == head->prev); } static inline void __list_splice(const struct list_head *list, struct list_head *prev, struct list_head *next) { struct list_head *first = list->next; struct list_head *last = list->prev; first->prev = prev; prev->next = first; last->next = next; next->prev = last; } /** * list_splice - join two lists * @list: the new list to add. * @head: the place to add it in the first list. */ static inline void list_splice(struct list_head *list, struct list_head *head) { if (!list_empty(list)) __list_splice(list, head, head->next); } /** * list_splice_tail - join two lists, each list being a queue * @list: the new list to add. * @head: the place to add it in the first list. */ static inline void list_splice_tail(struct list_head *list, struct list_head *head) { if (!list_empty(list)) __list_splice(list, head->prev, head); } /** * list_splice_init - join two lists and reinitialise the emptied list. * @list: the new list to add. * @head: the place to add it in the first list. * * The list at @list is reinitialised */ static inline void list_splice_init(struct list_head *list, struct list_head *head) { if (!list_empty(list)) { __list_splice(list, head, head->next); INIT_LIST_HEAD(list); } } /** * list_splice_tail_init - join two lists and reinitialise the emptied list * @list: the new list to add. * @head: the place to add it in the first list. * * Each of the lists is a queue. * The list at @list is reinitialised */ static inline void list_splice_tail_init(struct list_head *list, struct list_head *head) { if (!list_empty(list)) { __list_splice(list, head->prev, head); INIT_LIST_HEAD(list); } } /** * list_entry - get the struct for this entry * @ptr: the &struct list_head pointer. * @type: the type of the struct this is embedded in. * @member: the name of the list_struct within the struct. */ #define list_entry(ptr, type, member) \ container_of(ptr, type, member) /** * list_first_entry - get the first element from a list * @ptr: the list head to take the element from. * @type: the type of the struct this is embedded in. * @member: the name of the list_struct within the struct. * * Note, that list is expected to be not empty. */ #define list_first_entry(ptr, type, member) \ list_entry((ptr)->next, type, member) /** * list_next_entry - get the next element from a list * @ptr: the list head to take the element from. * @member: the name of the list_struct within the struct. * * Note, that next is expected to be not null. */ #define list_next_entry(ptr, member) \ list_entry((ptr)->member.next, typeof(*ptr), member) /** * list_for_each - iterate over a list * @pos: the &struct list_head to use as a loop cursor. * @head: the head for your list. */ #define list_for_each(pos, head) \ for (pos = (head)->next; pos != (head); \ pos = pos->next) /** * __list_for_each - iterate over a list * @pos: the &struct list_head to use as a loop cursor. * @head: the head for your list. * * This variant differs from list_for_each() in that it's the * simplest possible list iteration code, no prefetching is done. * Use this for code that knows the list to be very short (empty * or 1 entry) most of the time. */ #define __list_for_each(pos, head) \ for (pos = (head)->next; pos != (head); pos = pos->next) /** * list_for_each_prev - iterate over a list backwards * @pos: the &struct list_head to use as a loop cursor. * @head: the head for your list. */ #define list_for_each_prev(pos, head) \ for (pos = (head)->prev; pos != (head); \ pos = pos->prev) /** * list_for_each_safe - iterate over a list safe against removal of list entry * @pos: the &struct list_head to use as a loop cursor. * @n: another &struct list_head to use as temporary storage * @head: the head for your list. */ #define list_for_each_safe(pos, n, head) \ for (pos = (head)->next, n = pos->next; pos != (head); \ pos = n, n = pos->next) /** * list_for_each_entry - iterate over list of given type * @pos: the type * to use as a loop cursor. * @head: the head for your list. * @member: the name of the list_struct within the struct. */ #define list_for_each_entry(pos, head, member) \ for (pos = list_entry((head)->next, typeof(*pos), member); \ &pos->member != (head); \ pos = list_entry(pos->member.next, typeof(*pos), member)) /** * list_for_each_entry_reverse - iterate backwards over list of given type. * @pos: the type * to use as a loop cursor. * @head: the head for your list. * @member: the name of the list_struct within the struct. */ #define list_for_each_entry_reverse(pos, head, member) \ for (pos = list_entry((head)->prev, typeof(*pos), member); \ &pos->member != (head); \ pos = list_entry(pos->member.prev, typeof(*pos), member)) /** * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue * @pos: the type * to use as a start point * @head: the head of the list * @member: the name of the list_struct within the struct. * * Prepares a pos entry for use as a start point in list_for_each_entry_continue. */ #define list_prepare_entry(pos, head, member) \ ((pos) ? : list_entry(head, typeof(*pos), member)) /** * list_for_each_entry_continue - continue iteration over list of given type * @pos: the type * to use as a loop cursor. * @head: the head for your list. * @member: the name of the list_struct within the struct. * * Continue to iterate over list of given type, continuing after * the current position. */ #define list_for_each_entry_continue(pos, head, member) \ for (pos = list_entry(pos->member.next, typeof(*pos), member); \ &pos->member != (head); \ pos = list_entry(pos->member.next, typeof(*pos), member)) /** * list_for_each_entry_from - iterate over list of given type from the current point * @pos: the type * to use as a loop cursor. * @head: the head for your list. * @member: the name of the list_struct within the struct. * * Iterate over list of given type, continuing from current position. */ #define list_for_each_entry_from(pos, head, member) \ for (; &pos->member != (head); \ pos = list_entry(pos->member.next, typeof(*pos), member)) /** * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry * @pos: the type * to use as a loop cursor. * @n: another type * to use as temporary storage * @head: the head for your list. * @member: the name of the list_struct within the struct. */ #define list_for_each_entry_safe(pos, n, head, member) \ for (pos = list_entry((head)->next, typeof(*pos), member), \ n = list_entry(pos->member.next, typeof(*pos), member); \ &pos->member != (head); \ pos = n, n = list_entry(n->member.next, typeof(*n), member)) /** * list_for_each_entry_safe_continue * @pos: the type * to use as a loop cursor. * @n: another type * to use as temporary storage * @head: the head for your list. * @member: the name of the list_struct within the struct. * * Iterate over list of given type, continuing after current point, * safe against removal of list entry. */ #define list_for_each_entry_safe_continue(pos, n, head, member) \ for (pos = list_entry(pos->member.next, typeof(*pos), member), \ n = list_entry(pos->member.next, typeof(*pos), member); \ &pos->member != (head); \ pos = n, n = list_entry(n->member.next, typeof(*n), member)) /** * list_for_each_entry_safe_from * @pos: the type * to use as a loop cursor. * @n: another type * to use as temporary storage * @head: the head for your list. * @member: the name of the list_struct within the struct. * * Iterate over list of given type from current point, safe against * removal of list entry. */ #define list_for_each_entry_safe_from(pos, n, head, member) \ for (n = list_entry(pos->member.next, typeof(*pos), member); \ &pos->member != (head); \ pos = n, n = list_entry(n->member.next, typeof(*n), member)) /** * list_for_each_entry_safe_reverse * @pos: the type * to use as a loop cursor. * @n: another type * to use as temporary storage * @head: the head for your list. * @member: the name of the list_struct within the struct. * * Iterate backwards over list of given type, safe against removal * of list entry. */ #define list_for_each_entry_safe_reverse(pos, n, head, member) \ for (pos = list_entry((head)->prev, typeof(*pos), member), \ n = list_entry(pos->member.prev, typeof(*pos), member); \ &pos->member != (head); \ pos = n, n = list_entry(n->member.prev, typeof(*n), member)) #endif partclone-0.2.86/src/btrfs/list_sort.c000066400000000000000000000067561262102574200177120ustar00rootroot00000000000000/* * taken from linux kernel lib/list_sort.c, removed uneeded code and adapted * for btrfsprogs */ #include "kerncompat.h" #include "list_sort.h" #include "list.h" #define MAX_LIST_LENGTH_BITS 20 /* * Returns a list organized in an intermediate format suited * to chaining of merge() calls: null-terminated, no reserved or * sentinel head node, "prev" links not maintained. */ static struct list_head *merge(void *priv, int (*cmp)(void *priv, struct list_head *a, struct list_head *b), struct list_head *a, struct list_head *b) { struct list_head head, *tail = &head; while (a && b) { /* if equal, take 'a' -- important for sort stability */ if ((*cmp)(priv, a, b) <= 0) { tail->next = a; a = a->next; } else { tail->next = b; b = b->next; } tail = tail->next; } tail->next = a?:b; return head.next; } /* * Combine final list merge with restoration of standard doubly-linked * list structure. This approach duplicates code from merge(), but * runs faster than the tidier alternatives of either a separate final * prev-link restoration pass, or maintaining the prev links * throughout. */ static void merge_and_restore_back_links(void *priv, int (*cmp)(void *priv, struct list_head *a, struct list_head *b), struct list_head *head, struct list_head *a, struct list_head *b) { struct list_head *tail = head; while (a && b) { /* if equal, take 'a' -- important for sort stability */ if ((*cmp)(priv, a, b) <= 0) { tail->next = a; a->prev = tail; a = a->next; } else { tail->next = b; b->prev = tail; b = b->next; } tail = tail->next; } tail->next = a ? : b; do { /* * In worst cases this loop may run many iterations. * Continue callbacks to the client even though no * element comparison is needed, so the client's cmp() * routine can invoke cond_resched() periodically. */ (*cmp)(priv, tail->next, tail->next); tail->next->prev = tail; tail = tail->next; } while (tail->next); tail->next = head; head->prev = tail; } /** * list_sort - sort a list * @priv: private data, opaque to list_sort(), passed to @cmp * @head: the list to sort * @cmp: the elements comparison function * * This function implements "merge sort", which has O(nlog(n)) * complexity. * * The comparison function @cmp must return a negative value if @a * should sort before @b, and a positive value if @a should sort after * @b. If @a and @b are equivalent, and their original relative * ordering is to be preserved, @cmp must return 0. */ void list_sort(void *priv, struct list_head *head, int (*cmp)(void *priv, struct list_head *a, struct list_head *b)) { struct list_head *part[MAX_LIST_LENGTH_BITS+1]; /* sorted partial lists -- last slot is a sentinel */ int lev; /* index into part[] */ int max_lev = 0; struct list_head *list; if (list_empty(head)) return; memset(part, 0, sizeof(part)); head->prev->next = NULL; list = head->next; while (list) { struct list_head *cur = list; list = list->next; cur->next = NULL; for (lev = 0; part[lev]; lev++) { cur = merge(priv, cmp, part[lev], cur); part[lev] = NULL; } if (lev > max_lev) { if (lev >= ARRAY_SIZE(part)-1) { printf("list_sort: list passed to" " list_sort() too long for" " efficiency\n"); lev--; } max_lev = lev; } part[lev] = cur; } for (lev = 0; lev < max_lev; lev++) if (part[lev]) list = merge(priv, cmp, part[lev], list); merge_and_restore_back_links(priv, cmp, head, part[max_lev], list); } partclone-0.2.86/src/btrfs/list_sort.h000066400000000000000000000004431262102574200177020ustar00rootroot00000000000000/* * taken from linux kernel include/list_sort.h */ #ifndef _LINUX_LIST_SORT_H #define _LINUX_LIST_SORT_H #include "kerncompat.h" struct list_head; void list_sort(void *priv, struct list_head *head, int (*cmp)(void *priv, struct list_head *a, struct list_head *b)); #endif partclone-0.2.86/src/btrfs/math.h000066400000000000000000000016641262102574200166170ustar00rootroot00000000000000 /* * Copyright (C) 2012 FUJITSU LIMITED. All rights reserved. * Written by Miao Xie * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. */ #ifndef __BTRFS_MATH_H #define __BTRFS_MATH_H static inline u64 div_factor(u64 num, int factor) { if (factor == 10) return num; num *= factor; num /= 10; return num; } #endif partclone-0.2.86/src/btrfs/print-tree.c000066400000000000000000000747701262102574200177620ustar00rootroot00000000000000/* * Copyright (C) 2007 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. */ #include #include #include #include "kerncompat.h" #include "radix-tree.h" #include "ctree.h" #include "disk-io.h" #include "print-tree.h" #include "utils.h" static void print_dir_item_type(struct extent_buffer *eb, struct btrfs_dir_item *di) { u8 type = btrfs_dir_type(eb, di); switch (type) { case BTRFS_FT_REG_FILE: printf("FILE"); break; case BTRFS_FT_DIR: printf("DIR"); break; case BTRFS_FT_CHRDEV: printf("CHRDEV"); break; case BTRFS_FT_BLKDEV: printf("BLKDEV"); break; case BTRFS_FT_FIFO: printf("FIFO"); break; case BTRFS_FT_SOCK: printf("SOCK"); break; case BTRFS_FT_SYMLINK: printf("SYMLINK"); break; case BTRFS_FT_XATTR: printf("XATTR"); break; default: printf("%u", type); } } static int print_dir_item(struct extent_buffer *eb, struct btrfs_item *item, struct btrfs_dir_item *di) { u32 total; u32 cur = 0; u32 len; u32 name_len; u32 data_len; char namebuf[BTRFS_NAME_LEN]; struct btrfs_disk_key location; total = btrfs_item_size(eb, item); while(cur < total) { btrfs_dir_item_key(eb, di, &location); printf("\t\tlocation "); btrfs_print_key(&location); printf(" type "); print_dir_item_type(eb, di); printf("\n"); name_len = btrfs_dir_name_len(eb, di); data_len = btrfs_dir_data_len(eb, di); len = (name_len <= sizeof(namebuf))? name_len: sizeof(namebuf); read_extent_buffer(eb, namebuf, (unsigned long)(di + 1), len); printf("\t\tnamelen %u datalen %u name: %.*s\n", name_len, data_len, len, namebuf); if (data_len) { len = (data_len <= sizeof(namebuf))? data_len: sizeof(namebuf); read_extent_buffer(eb, namebuf, (unsigned long)(di + 1) + name_len, len); printf("\t\tdata %.*s\n", len, namebuf); } len = sizeof(*di) + name_len + data_len; di = (struct btrfs_dir_item *)((char *)di + len); cur += len; } return 0; } static int print_inode_extref_item(struct extent_buffer *eb, struct btrfs_item *item, struct btrfs_inode_extref *extref) { u32 total; u32 cur = 0; u32 len; u32 name_len = 0; u64 index = 0; u64 parent_objid; char namebuf[BTRFS_NAME_LEN]; total = btrfs_item_size(eb, item); while (cur < total) { index = btrfs_inode_extref_index(eb, extref); name_len = btrfs_inode_extref_name_len(eb, extref); parent_objid = btrfs_inode_extref_parent(eb, extref); len = (name_len <= sizeof(namebuf))? name_len: sizeof(namebuf); read_extent_buffer(eb, namebuf, (unsigned long)(extref->name), len); printf("\t\tinode extref index %llu parent %llu namelen %u " "name: %.*s\n", (unsigned long long)index, (unsigned long long)parent_objid, name_len, len, namebuf); len = sizeof(*extref) + name_len; extref = (struct btrfs_inode_extref *)((char *)extref + len); cur += len; } return 0; } static int print_inode_ref_item(struct extent_buffer *eb, struct btrfs_item *item, struct btrfs_inode_ref *ref) { u32 total; u32 cur = 0; u32 len; u32 name_len; u64 index; char namebuf[BTRFS_NAME_LEN]; total = btrfs_item_size(eb, item); while(cur < total) { name_len = btrfs_inode_ref_name_len(eb, ref); index = btrfs_inode_ref_index(eb, ref); len = (name_len <= sizeof(namebuf))? name_len: sizeof(namebuf); read_extent_buffer(eb, namebuf, (unsigned long)(ref + 1), len); printf("\t\tinode ref index %llu namelen %u name: %.*s\n", (unsigned long long)index, name_len, len, namebuf); len = sizeof(*ref) + name_len; ref = (struct btrfs_inode_ref *)((char *)ref + len); cur += len; } return 0; } /* Caller should ensure sizeof(*ret)>=21 "DATA|METADATA|RAID10" */ static void bg_flags_to_str(u64 flags, char *ret) { int empty = 1; if (flags & BTRFS_BLOCK_GROUP_DATA) { empty = 0; strcpy(ret, "DATA"); } if (flags & BTRFS_BLOCK_GROUP_METADATA) { if (!empty) strcat(ret, "|"); strcat(ret, "METADATA"); } if (flags & BTRFS_BLOCK_GROUP_SYSTEM) { if (!empty) strcat(ret, "|"); strcat(ret, "SYSTEM"); } switch (flags & BTRFS_BLOCK_GROUP_PROFILE_MASK) { case BTRFS_BLOCK_GROUP_RAID0: strcat(ret, "|RAID0"); break; case BTRFS_BLOCK_GROUP_RAID1: strcat(ret, "|RAID1"); break; case BTRFS_BLOCK_GROUP_DUP: strcat(ret, "|DUP"); break; case BTRFS_BLOCK_GROUP_RAID10: strcat(ret, "|RAID10"); break; case BTRFS_BLOCK_GROUP_RAID5: strcat(ret, "|RAID5"); break; case BTRFS_BLOCK_GROUP_RAID6: strcat(ret, "|RAID6"); break; default: break; } } void print_chunk(struct extent_buffer *eb, struct btrfs_chunk *chunk) { int num_stripes = btrfs_chunk_num_stripes(eb, chunk); int i; char chunk_flags_str[32] = {0}; bg_flags_to_str(btrfs_chunk_type(eb, chunk), chunk_flags_str); printf("\t\tchunk length %llu owner %llu type %s num_stripes %d\n", (unsigned long long)btrfs_chunk_length(eb, chunk), (unsigned long long)btrfs_chunk_owner(eb, chunk), chunk_flags_str, num_stripes); for (i = 0 ; i < num_stripes ; i++) { printf("\t\t\tstripe %d devid %llu offset %llu\n", i, (unsigned long long)btrfs_stripe_devid_nr(eb, chunk, i), (unsigned long long)btrfs_stripe_offset_nr(eb, chunk, i)); } } static void print_dev_item(struct extent_buffer *eb, struct btrfs_dev_item *dev_item) { char disk_uuid_c[BTRFS_UUID_UNPARSED_SIZE]; u8 disk_uuid[BTRFS_UUID_SIZE]; read_extent_buffer(eb, disk_uuid, (unsigned long)btrfs_device_uuid(dev_item), BTRFS_UUID_SIZE); uuid_unparse(disk_uuid, disk_uuid_c); printf("\t\tdev item devid %llu " "total_bytes %llu bytes used %Lu\n" "\t\tdev uuid %s\n", (unsigned long long)btrfs_device_id(eb, dev_item), (unsigned long long)btrfs_device_total_bytes(eb, dev_item), (unsigned long long)btrfs_device_bytes_used(eb, dev_item), disk_uuid_c); } static void print_uuids(struct extent_buffer *eb) { char fs_uuid[BTRFS_UUID_UNPARSED_SIZE]; char chunk_uuid[BTRFS_UUID_UNPARSED_SIZE]; u8 disk_uuid[BTRFS_UUID_SIZE]; read_extent_buffer(eb, disk_uuid, btrfs_header_fsid(), BTRFS_FSID_SIZE); fs_uuid[BTRFS_UUID_UNPARSED_SIZE - 1] = '\0'; uuid_unparse(disk_uuid, fs_uuid); read_extent_buffer(eb, disk_uuid, btrfs_header_chunk_tree_uuid(eb), BTRFS_UUID_SIZE); chunk_uuid[BTRFS_UUID_UNPARSED_SIZE - 1] = '\0'; uuid_unparse(disk_uuid, chunk_uuid); printf("fs uuid %s\nchunk uuid %s\n", fs_uuid, chunk_uuid); } static void print_file_extent_item(struct extent_buffer *eb, struct btrfs_item *item, int slot, struct btrfs_file_extent_item *fi) { int extent_type = btrfs_file_extent_type(eb, fi); if (extent_type == BTRFS_FILE_EXTENT_INLINE) { printf("\t\tinline extent data size %u " "ram %u compress %d\n", btrfs_file_extent_inline_item_len(eb, item), btrfs_file_extent_inline_len(eb, slot, fi), btrfs_file_extent_compression(eb, fi)); return; } if (extent_type == BTRFS_FILE_EXTENT_PREALLOC) { printf("\t\tprealloc data disk byte %llu nr %llu\n", (unsigned long long)btrfs_file_extent_disk_bytenr(eb, fi), (unsigned long long)btrfs_file_extent_disk_num_bytes(eb, fi)); printf("\t\tprealloc data offset %llu nr %llu\n", (unsigned long long)btrfs_file_extent_offset(eb, fi), (unsigned long long)btrfs_file_extent_num_bytes(eb, fi)); return; } printf("\t\textent data disk byte %llu nr %llu\n", (unsigned long long)btrfs_file_extent_disk_bytenr(eb, fi), (unsigned long long)btrfs_file_extent_disk_num_bytes(eb, fi)); printf("\t\textent data offset %llu nr %llu ram %llu\n", (unsigned long long)btrfs_file_extent_offset(eb, fi), (unsigned long long)btrfs_file_extent_num_bytes(eb, fi), (unsigned long long)btrfs_file_extent_ram_bytes(eb, fi)); printf("\t\textent compression %d\n", btrfs_file_extent_compression(eb, fi)); } /* Caller should ensure sizeof(*ret) >= 16("DATA|TREE_BLOCK") */ static void extent_flags_to_str(u64 flags, char *ret) { int empty = 1; if (flags & BTRFS_EXTENT_FLAG_DATA) { empty = 0; strcpy(ret, "DATA"); } if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) { if (!empty) { empty = 0; strcat(ret, "|"); } strcat(ret, "TREE_BLOCK"); } } void print_extent_item(struct extent_buffer *eb, int slot, int metadata) { struct btrfs_extent_item *ei; struct btrfs_extent_inline_ref *iref; struct btrfs_extent_data_ref *dref; struct btrfs_shared_data_ref *sref; struct btrfs_disk_key key; unsigned long end; unsigned long ptr; int type; u32 item_size = btrfs_item_size_nr(eb, slot); u64 flags; u64 offset; char flags_str[32] = {0}; if (item_size < sizeof(*ei)) { #ifdef BTRFS_COMPAT_EXTENT_TREE_V0 struct btrfs_extent_item_v0 *ei0; BUG_ON(item_size != sizeof(*ei0)); ei0 = btrfs_item_ptr(eb, slot, struct btrfs_extent_item_v0); printf("\t\textent refs %u\n", btrfs_extent_refs_v0(eb, ei0)); return; #else BUG(); #endif } ei = btrfs_item_ptr(eb, slot, struct btrfs_extent_item); flags = btrfs_extent_flags(eb, ei); extent_flags_to_str(flags, flags_str); printf("\t\textent refs %llu gen %llu flags %s\n", (unsigned long long)btrfs_extent_refs(eb, ei), (unsigned long long)btrfs_extent_generation(eb, ei), flags_str); if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK && !metadata) { struct btrfs_tree_block_info *info; info = (struct btrfs_tree_block_info *)(ei + 1); btrfs_tree_block_key(eb, info, &key); printf("\t\ttree block "); btrfs_print_key(&key); printf(" level %d\n", btrfs_tree_block_level(eb, info)); iref = (struct btrfs_extent_inline_ref *)(info + 1); } else if (metadata) { struct btrfs_key tmp; btrfs_item_key_to_cpu(eb, &tmp, slot); printf("\t\ttree block skinny level %d\n", (int)tmp.offset); iref = (struct btrfs_extent_inline_ref *)(ei + 1); } else{ iref = (struct btrfs_extent_inline_ref *)(ei + 1); } ptr = (unsigned long)iref; end = (unsigned long)ei + item_size; while (ptr < end) { iref = (struct btrfs_extent_inline_ref *)ptr; type = btrfs_extent_inline_ref_type(eb, iref); offset = btrfs_extent_inline_ref_offset(eb, iref); switch (type) { case BTRFS_TREE_BLOCK_REF_KEY: printf("\t\ttree block backref root %llu\n", (unsigned long long)offset); break; case BTRFS_SHARED_BLOCK_REF_KEY: printf("\t\tshared block backref parent %llu\n", (unsigned long long)offset); break; case BTRFS_EXTENT_DATA_REF_KEY: dref = (struct btrfs_extent_data_ref *)(&iref->offset); printf("\t\textent data backref root %llu " "objectid %llu offset %llu count %u\n", (unsigned long long)btrfs_extent_data_ref_root(eb, dref), (unsigned long long)btrfs_extent_data_ref_objectid(eb, dref), (unsigned long long)btrfs_extent_data_ref_offset(eb, dref), btrfs_extent_data_ref_count(eb, dref)); break; case BTRFS_SHARED_DATA_REF_KEY: sref = (struct btrfs_shared_data_ref *)(iref + 1); printf("\t\tshared data backref parent %llu count %u\n", (unsigned long long)offset, btrfs_shared_data_ref_count(eb, sref)); break; default: return; } ptr += btrfs_extent_inline_ref_size(type); } WARN_ON(ptr > end); } #ifdef BTRFS_COMPAT_EXTENT_TREE_V0 static void print_extent_ref_v0(struct extent_buffer *eb, int slot) { struct btrfs_extent_ref_v0 *ref0; ref0 = btrfs_item_ptr(eb, slot, struct btrfs_extent_ref_v0); printf("\t\textent back ref root %llu gen %llu " "owner %llu num_refs %lu\n", (unsigned long long)btrfs_ref_root_v0(eb, ref0), (unsigned long long)btrfs_ref_generation_v0(eb, ref0), (unsigned long long)btrfs_ref_objectid_v0(eb, ref0), (unsigned long)btrfs_ref_count_v0(eb, ref0)); } #endif static void print_root_ref(struct extent_buffer *leaf, int slot, char *tag) { struct btrfs_root_ref *ref; char namebuf[BTRFS_NAME_LEN]; int namelen; ref = btrfs_item_ptr(leaf, slot, struct btrfs_root_ref); namelen = btrfs_root_ref_name_len(leaf, ref); read_extent_buffer(leaf, namebuf, (unsigned long)(ref + 1), namelen); printf("\t\troot %s key dirid %llu sequence %llu name %.*s\n", tag, (unsigned long long)btrfs_root_ref_dirid(leaf, ref), (unsigned long long)btrfs_root_ref_sequence(leaf, ref), namelen, namebuf); } static int count_bytes(void *buf, int len, char b) { int cnt = 0; int i; for (i = 0; i < len; i++) { if (((char*)buf)[i] == b) cnt++; } return cnt; } static void print_root(struct extent_buffer *leaf, int slot) { struct btrfs_root_item *ri; struct btrfs_root_item root_item; int len; char uuid_str[BTRFS_UUID_UNPARSED_SIZE]; ri = btrfs_item_ptr(leaf, slot, struct btrfs_root_item); len = btrfs_item_size_nr(leaf, slot); memset(&root_item, 0, sizeof(root_item)); read_extent_buffer(leaf, &root_item, (unsigned long)ri, len); printf("\t\troot data bytenr %llu level %d dirid %llu refs %u gen %llu\n", (unsigned long long)btrfs_root_bytenr(&root_item), btrfs_root_level(&root_item), (unsigned long long)btrfs_root_dirid(&root_item), btrfs_root_refs(&root_item), (unsigned long long)btrfs_root_generation(&root_item)); if (root_item.generation == root_item.generation_v2) { uuid_unparse(root_item.uuid, uuid_str); printf("\t\tuuid %s\n", uuid_str); if (count_bytes(root_item.parent_uuid, BTRFS_UUID_SIZE, 0) != BTRFS_UUID_SIZE) { uuid_unparse(root_item.parent_uuid, uuid_str); printf("\t\tparent_uuid %s\n", uuid_str); } if (count_bytes(root_item.received_uuid, BTRFS_UUID_SIZE, 0) != BTRFS_UUID_SIZE) { uuid_unparse(root_item.received_uuid, uuid_str); printf("\t\treceived_uuid %s\n", uuid_str); } if (root_item.ctransid) { printf("\t\tctransid %llu otransid %llu stransid %llu rtransid %llu\n", btrfs_root_ctransid(&root_item), btrfs_root_otransid(&root_item), btrfs_root_stransid(&root_item), btrfs_root_rtransid(&root_item)); } } if (btrfs_root_refs(&root_item) == 0) { struct btrfs_key drop_key; btrfs_disk_key_to_cpu(&drop_key, &root_item.drop_progress); printf("\t\tdrop "); btrfs_print_key(&root_item.drop_progress); printf(" level %d\n", root_item.drop_level); } } static void print_free_space_header(struct extent_buffer *leaf, int slot) { struct btrfs_free_space_header *header; struct btrfs_disk_key location; header = btrfs_item_ptr(leaf, slot, struct btrfs_free_space_header); btrfs_free_space_key(leaf, header, &location); printf("\t\tlocation "); btrfs_print_key(&location); printf("\n"); printf("\t\tcache generation %llu entries %llu bitmaps %llu\n", (unsigned long long)btrfs_free_space_generation(leaf, header), (unsigned long long)btrfs_free_space_entries(leaf, header), (unsigned long long)btrfs_free_space_bitmaps(leaf, header)); } static void print_key_type(u64 objectid, u8 type) { if (type == 0 && objectid == BTRFS_FREE_SPACE_OBJECTID) { printf("UNTYPED"); return; } switch (type) { case BTRFS_INODE_ITEM_KEY: printf("INODE_ITEM"); break; case BTRFS_INODE_REF_KEY: printf("INODE_REF"); break; case BTRFS_INODE_EXTREF_KEY: printf("INODE_EXTREF"); break; case BTRFS_DIR_ITEM_KEY: printf("DIR_ITEM"); break; case BTRFS_DIR_INDEX_KEY: printf("DIR_INDEX"); break; case BTRFS_DIR_LOG_ITEM_KEY: printf("DIR_LOG_ITEM"); break; case BTRFS_DIR_LOG_INDEX_KEY: printf("DIR_LOG_INDEX"); break; case BTRFS_XATTR_ITEM_KEY: printf("XATTR_ITEM"); break; case BTRFS_ORPHAN_ITEM_KEY: printf("ORPHAN_ITEM"); break; case BTRFS_ROOT_ITEM_KEY: printf("ROOT_ITEM"); break; case BTRFS_ROOT_REF_KEY: printf("ROOT_REF"); break; case BTRFS_ROOT_BACKREF_KEY: printf("ROOT_BACKREF"); break; case BTRFS_EXTENT_ITEM_KEY: printf("EXTENT_ITEM"); break; case BTRFS_METADATA_ITEM_KEY: printf("METADATA_ITEM"); break; case BTRFS_TREE_BLOCK_REF_KEY: printf("TREE_BLOCK_REF"); break; case BTRFS_SHARED_BLOCK_REF_KEY: printf("SHARED_BLOCK_REF"); break; case BTRFS_EXTENT_DATA_REF_KEY: printf("EXTENT_DATA_REF"); break; case BTRFS_SHARED_DATA_REF_KEY: printf("SHARED_DATA_REF"); break; case BTRFS_EXTENT_REF_V0_KEY: printf("EXTENT_REF_V0"); break; case BTRFS_CSUM_ITEM_KEY: printf("CSUM_ITEM"); break; case BTRFS_EXTENT_CSUM_KEY: printf("EXTENT_CSUM"); break; case BTRFS_EXTENT_DATA_KEY: printf("EXTENT_DATA"); break; case BTRFS_BLOCK_GROUP_ITEM_KEY: printf("BLOCK_GROUP_ITEM"); break; case BTRFS_CHUNK_ITEM_KEY: printf("CHUNK_ITEM"); break; case BTRFS_DEV_ITEM_KEY: printf("DEV_ITEM"); break; case BTRFS_DEV_EXTENT_KEY: printf("DEV_EXTENT"); break; case BTRFS_BALANCE_ITEM_KEY: printf("BALANCE_ITEM"); break; case BTRFS_DEV_REPLACE_KEY: printf("DEV_REPLACE_ITEM"); break; case BTRFS_STRING_ITEM_KEY: printf("STRING_ITEM"); break; case BTRFS_QGROUP_STATUS_KEY: printf("BTRFS_STATUS_KEY"); break; case BTRFS_QGROUP_RELATION_KEY: printf("BTRFS_QGROUP_RELATION_KEY"); break; case BTRFS_QGROUP_INFO_KEY: printf("BTRFS_QGROUP_INFO_KEY"); break; case BTRFS_QGROUP_LIMIT_KEY: printf("BTRFS_QGROUP_LIMIT_KEY"); break; case BTRFS_DEV_STATS_KEY: printf("DEV_STATS_ITEM"); break; case BTRFS_UUID_KEY_SUBVOL: printf("BTRFS_UUID_KEY_SUBVOL"); break; case BTRFS_UUID_KEY_RECEIVED_SUBVOL: printf("BTRFS_UUID_KEY_RECEIVED_SUBVOL"); break; default: printf("UNKNOWN.%d", type); }; } static void print_objectid(u64 objectid, u8 type) { switch (type) { case BTRFS_DEV_EXTENT_KEY: printf("%llu", (unsigned long long)objectid); /* device id */ return; case BTRFS_QGROUP_RELATION_KEY: printf("%llu/%llu", objectid >> 48, objectid & ((1ll << 48) - 1)); return; case BTRFS_UUID_KEY_SUBVOL: case BTRFS_UUID_KEY_RECEIVED_SUBVOL: printf("0x%016llx", (unsigned long long)objectid); return; } switch (objectid) { case BTRFS_ROOT_TREE_OBJECTID: if (type == BTRFS_DEV_ITEM_KEY) printf("DEV_ITEMS"); else printf("ROOT_TREE"); break; case BTRFS_EXTENT_TREE_OBJECTID: printf("EXTENT_TREE"); break; case BTRFS_CHUNK_TREE_OBJECTID: printf("CHUNK_TREE"); break; case BTRFS_DEV_TREE_OBJECTID: printf("DEV_TREE"); break; case BTRFS_FS_TREE_OBJECTID: printf("FS_TREE"); break; case BTRFS_ROOT_TREE_DIR_OBJECTID: printf("ROOT_TREE_DIR"); break; case BTRFS_CSUM_TREE_OBJECTID: printf("CSUM_TREE"); break; case BTRFS_BALANCE_OBJECTID: printf("BALANCE"); break; case BTRFS_ORPHAN_OBJECTID: printf("ORPHAN"); break; case BTRFS_TREE_LOG_OBJECTID: printf("TREE_LOG"); break; case BTRFS_TREE_LOG_FIXUP_OBJECTID: printf("LOG_FIXUP"); break; case BTRFS_TREE_RELOC_OBJECTID: printf("TREE_RELOC"); break; case BTRFS_DATA_RELOC_TREE_OBJECTID: printf("DATA_RELOC_TREE"); break; case BTRFS_EXTENT_CSUM_OBJECTID: printf("EXTENT_CSUM"); break; case BTRFS_FREE_SPACE_OBJECTID: printf("FREE_SPACE"); break; case BTRFS_FREE_INO_OBJECTID: printf("FREE_INO"); break; case BTRFS_QUOTA_TREE_OBJECTID: printf("QUOTA_TREE"); break; case BTRFS_UUID_TREE_OBJECTID: printf("UUID_TREE"); break; case BTRFS_MULTIPLE_OBJECTIDS: printf("MULTIPLE"); break; case (u64)-1: printf("-1"); break; case BTRFS_FIRST_CHUNK_TREE_OBJECTID: if (type == BTRFS_CHUNK_ITEM_KEY) { printf("FIRST_CHUNK_TREE"); break; } /* fall-thru */ default: printf("%llu", (unsigned long long)objectid); } } void btrfs_print_key(struct btrfs_disk_key *disk_key) { u64 objectid = btrfs_disk_key_objectid(disk_key); u8 type = btrfs_disk_key_type(disk_key); u64 offset = btrfs_disk_key_offset(disk_key); printf("key ("); print_objectid(objectid, type); printf(" "); print_key_type(objectid, type); switch (type) { case BTRFS_QGROUP_RELATION_KEY: case BTRFS_QGROUP_INFO_KEY: case BTRFS_QGROUP_LIMIT_KEY: printf(" %llu/%llu)", (unsigned long long)(offset >> 48), (unsigned long long)(offset & ((1ll << 48) - 1))); break; case BTRFS_UUID_KEY_SUBVOL: case BTRFS_UUID_KEY_RECEIVED_SUBVOL: printf(" 0x%016llx)", (unsigned long long)offset); break; default: if (offset == (u64)-1) printf(" -1)"); else printf(" %llu)", (unsigned long long)offset); break; } } static void print_uuid_item(struct extent_buffer *l, unsigned long offset, u32 item_size) { if (item_size & (sizeof(u64) - 1)) { printf("btrfs: uuid item with illegal size %lu!\n", (unsigned long)item_size); return; } while (item_size) { __le64 subvol_id; read_extent_buffer(l, &subvol_id, offset, sizeof(u64)); printf("\t\tsubvol_id %llu\n", (unsigned long long)le64_to_cpu(subvol_id)); item_size -= sizeof(u64); offset += sizeof(u64); } } void btrfs_print_leaf(struct btrfs_root *root, struct extent_buffer *l) { int i; char *str; struct btrfs_item *item; struct btrfs_dir_item *di; struct btrfs_inode_item *ii; struct btrfs_file_extent_item *fi; struct btrfs_block_group_item *bi; struct btrfs_extent_data_ref *dref; struct btrfs_shared_data_ref *sref; struct btrfs_inode_ref *iref; struct btrfs_inode_extref *iref2; struct btrfs_dev_extent *dev_extent; struct btrfs_disk_key disk_key; struct btrfs_block_group_item bg_item; struct btrfs_dir_log_item *dlog; struct btrfs_qgroup_info_item *qg_info; struct btrfs_qgroup_limit_item *qg_limit; struct btrfs_qgroup_status_item *qg_status; u32 nr = btrfs_header_nritems(l); u64 objectid; u32 type; char bg_flags_str[32]; printf("leaf %llu items %d free space %d generation %llu owner %llu\n", (unsigned long long)btrfs_header_bytenr(l), nr, btrfs_leaf_free_space(root, l), (unsigned long long)btrfs_header_generation(l), (unsigned long long)btrfs_header_owner(l)); print_uuids(l); fflush(stdout); for (i = 0 ; i < nr ; i++) { item = btrfs_item_nr(i); btrfs_item_key(l, &disk_key, i); objectid = btrfs_disk_key_objectid(&disk_key); type = btrfs_disk_key_type(&disk_key); printf("\titem %d ", i); btrfs_print_key(&disk_key); printf(" itemoff %d itemsize %d\n", btrfs_item_offset(l, item), btrfs_item_size(l, item)); if (type == 0 && objectid == BTRFS_FREE_SPACE_OBJECTID) print_free_space_header(l, i); switch (type) { case BTRFS_INODE_ITEM_KEY: ii = btrfs_item_ptr(l, i, struct btrfs_inode_item); printf("\t\tinode generation %llu transid %llu size %llu block group %llu mode %o links %u uid %u gid %u rdev %llu flags 0x%llx\n", (unsigned long long)btrfs_inode_generation(l, ii), (unsigned long long)btrfs_inode_transid(l, ii), (unsigned long long)btrfs_inode_size(l, ii), (unsigned long long)btrfs_inode_block_group(l,ii), btrfs_inode_mode(l, ii), btrfs_inode_nlink(l, ii), btrfs_inode_uid(l, ii), btrfs_inode_gid(l, ii), (unsigned long long)btrfs_inode_rdev(l,ii), (unsigned long long)btrfs_inode_flags(l,ii)); break; case BTRFS_INODE_REF_KEY: iref = btrfs_item_ptr(l, i, struct btrfs_inode_ref); print_inode_ref_item(l, item, iref); break; case BTRFS_INODE_EXTREF_KEY: iref2 = btrfs_item_ptr(l, i, struct btrfs_inode_extref); print_inode_extref_item(l, item, iref2); break; case BTRFS_DIR_ITEM_KEY: case BTRFS_DIR_INDEX_KEY: case BTRFS_XATTR_ITEM_KEY: di = btrfs_item_ptr(l, i, struct btrfs_dir_item); print_dir_item(l, item, di); break; case BTRFS_DIR_LOG_INDEX_KEY: case BTRFS_DIR_LOG_ITEM_KEY: dlog = btrfs_item_ptr(l, i, struct btrfs_dir_log_item); printf("\t\tdir log end %Lu\n", (unsigned long long)btrfs_dir_log_end(l, dlog)); break; case BTRFS_ORPHAN_ITEM_KEY: printf("\t\torphan item\n"); break; case BTRFS_ROOT_ITEM_KEY: print_root(l, i); break; case BTRFS_ROOT_REF_KEY: print_root_ref(l, i, "ref"); break; case BTRFS_ROOT_BACKREF_KEY: print_root_ref(l, i, "backref"); break; case BTRFS_EXTENT_ITEM_KEY: print_extent_item(l, i, 0); break; case BTRFS_METADATA_ITEM_KEY: print_extent_item(l, i, 1); break; case BTRFS_TREE_BLOCK_REF_KEY: printf("\t\ttree block backref\n"); break; case BTRFS_SHARED_BLOCK_REF_KEY: printf("\t\tshared block backref\n"); break; case BTRFS_EXTENT_DATA_REF_KEY: dref = btrfs_item_ptr(l, i, struct btrfs_extent_data_ref); printf("\t\textent data backref root %llu " "objectid %llu offset %llu count %u\n", (unsigned long long)btrfs_extent_data_ref_root(l, dref), (unsigned long long)btrfs_extent_data_ref_objectid(l, dref), (unsigned long long)btrfs_extent_data_ref_offset(l, dref), btrfs_extent_data_ref_count(l, dref)); break; case BTRFS_SHARED_DATA_REF_KEY: sref = btrfs_item_ptr(l, i, struct btrfs_shared_data_ref); printf("\t\tshared data backref count %u\n", btrfs_shared_data_ref_count(l, sref)); break; case BTRFS_EXTENT_REF_V0_KEY: #ifdef BTRFS_COMPAT_EXTENT_TREE_V0 print_extent_ref_v0(l, i); #else BUG(); #endif break; case BTRFS_CSUM_ITEM_KEY: printf("\t\tcsum item\n"); break; case BTRFS_EXTENT_CSUM_KEY: printf("\t\textent csum item\n"); break; case BTRFS_EXTENT_DATA_KEY: fi = btrfs_item_ptr(l, i, struct btrfs_file_extent_item); print_file_extent_item(l, item, i, fi); break; case BTRFS_BLOCK_GROUP_ITEM_KEY: bi = btrfs_item_ptr(l, i, struct btrfs_block_group_item); read_extent_buffer(l, &bg_item, (unsigned long)bi, sizeof(bg_item)); memset(bg_flags_str, 0, sizeof(bg_flags_str)); bg_flags_to_str(btrfs_block_group_flags(&bg_item), bg_flags_str); printf("\t\tblock group used %llu chunk_objectid %llu flags %s\n", (unsigned long long)btrfs_block_group_used(&bg_item), (unsigned long long)btrfs_block_group_chunk_objectid(&bg_item), bg_flags_str); break; case BTRFS_CHUNK_ITEM_KEY: print_chunk(l, btrfs_item_ptr(l, i, struct btrfs_chunk)); break; case BTRFS_DEV_ITEM_KEY: print_dev_item(l, btrfs_item_ptr(l, i, struct btrfs_dev_item)); break; case BTRFS_DEV_EXTENT_KEY: dev_extent = btrfs_item_ptr(l, i, struct btrfs_dev_extent); printf("\t\tdev extent chunk_tree %llu\n" "\t\tchunk objectid %llu chunk offset %llu " "length %llu\n", (unsigned long long) btrfs_dev_extent_chunk_tree(l, dev_extent), (unsigned long long) btrfs_dev_extent_chunk_objectid(l, dev_extent), (unsigned long long) btrfs_dev_extent_chunk_offset(l, dev_extent), (unsigned long long) btrfs_dev_extent_length(l, dev_extent)); break; case BTRFS_QGROUP_STATUS_KEY: qg_status = btrfs_item_ptr(l, i, struct btrfs_qgroup_status_item); printf("\t\tversion %llu generation %llu flags %#llx " "scan %lld\n", (unsigned long long) btrfs_qgroup_status_version(l, qg_status), (unsigned long long) btrfs_qgroup_status_generation(l, qg_status), (unsigned long long) btrfs_qgroup_status_flags(l, qg_status), (unsigned long long) btrfs_qgroup_status_scan(l, qg_status)); break; case BTRFS_QGROUP_RELATION_KEY: break; case BTRFS_QGROUP_INFO_KEY: qg_info = btrfs_item_ptr(l, i, struct btrfs_qgroup_info_item); printf("\t\tgeneration %llu\n" "\t\treferenced %llu referenced compressed %llu\n" "\t\texclusive %llu exclusive compressed %llu\n", (unsigned long long) btrfs_qgroup_info_generation(l, qg_info), (unsigned long long) btrfs_qgroup_info_referenced(l, qg_info), (unsigned long long) btrfs_qgroup_info_referenced_compressed(l, qg_info), (unsigned long long) btrfs_qgroup_info_exclusive(l, qg_info), (unsigned long long) btrfs_qgroup_info_exclusive_compressed(l, qg_info)); break; case BTRFS_QGROUP_LIMIT_KEY: qg_limit = btrfs_item_ptr(l, i, struct btrfs_qgroup_limit_item); printf("\t\tflags %llx\n" "\t\tmax referenced %lld max exclusive %lld\n" "\t\trsv referenced %lld rsv exclusive %lld\n", (unsigned long long) btrfs_qgroup_limit_flags(l, qg_limit), (long long) btrfs_qgroup_limit_max_referenced(l, qg_limit), (long long) btrfs_qgroup_limit_max_exclusive(l, qg_limit), (long long) btrfs_qgroup_limit_rsv_referenced(l, qg_limit), (long long) btrfs_qgroup_limit_rsv_exclusive(l, qg_limit)); break; case BTRFS_UUID_KEY_SUBVOL: case BTRFS_UUID_KEY_RECEIVED_SUBVOL: print_uuid_item(l, btrfs_item_ptr_offset(l, i), btrfs_item_size_nr(l, i)); break; case BTRFS_STRING_ITEM_KEY: /* dirty, but it's simple */ str = l->data + btrfs_item_ptr_offset(l, i); printf("\t\titem data %.*s\n", btrfs_item_size(l, item), str); break; case BTRFS_DEV_STATS_KEY: printf("\t\tdevice stats\n"); break; }; fflush(stdout); } } void btrfs_print_tree(struct btrfs_root *root, struct extent_buffer *eb, int follow) { int i; u32 nr; u32 size; struct btrfs_disk_key disk_key; struct btrfs_key key; if (!eb) return; nr = btrfs_header_nritems(eb); if (btrfs_is_leaf(eb)) { btrfs_print_leaf(root, eb); return; } printf("node %llu level %d items %d free %u generation %llu owner %llu\n", (unsigned long long)eb->start, btrfs_header_level(eb), nr, (u32)BTRFS_NODEPTRS_PER_BLOCK(root) - nr, (unsigned long long)btrfs_header_generation(eb), (unsigned long long)btrfs_header_owner(eb)); print_uuids(eb); fflush(stdout); size = btrfs_level_size(root, btrfs_header_level(eb) - 1); for (i = 0; i < nr; i++) { u64 blocknr = btrfs_node_blockptr(eb, i); btrfs_node_key(eb, &disk_key, i); btrfs_disk_key_to_cpu(&key, &disk_key); printf("\t"); btrfs_print_key(&disk_key); printf(" block %llu (%llu) gen %llu\n", (unsigned long long)blocknr, (unsigned long long)blocknr / size, (unsigned long long)btrfs_node_ptr_generation(eb, i)); fflush(stdout); } if (!follow) return; for (i = 0; i < nr; i++) { struct extent_buffer *next = read_tree_block(root, btrfs_node_blockptr(eb, i), size, btrfs_node_ptr_generation(eb, i)); if (!next) { fprintf(stderr, "failed to read %llu in tree %llu\n", (unsigned long long)btrfs_node_blockptr(eb, i), (unsigned long long)btrfs_header_owner(eb)); continue; } if (btrfs_is_leaf(next) && btrfs_header_level(eb) != 1) BUG(); if (btrfs_header_level(next) != btrfs_header_level(eb) - 1) BUG(); btrfs_print_tree(root, next, 1); free_extent_buffer(next); } } partclone-0.2.86/src/btrfs/print-tree.h000066400000000000000000000021361262102574200177520ustar00rootroot00000000000000/* * Copyright (C) 2007 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. */ #ifndef __PRINT_TREE_ #define __PRINT_TREE_ void btrfs_print_leaf(struct btrfs_root *root, struct extent_buffer *l); void btrfs_print_tree(struct btrfs_root *root, struct extent_buffer *t, int follow); void btrfs_print_key(struct btrfs_disk_key *disk_key); void print_chunk(struct extent_buffer *eb, struct btrfs_chunk *chunk); void print_extent_item(struct extent_buffer *eb, int slot, int metadata); #endif partclone-0.2.86/src/btrfs/qgroup-verify.c000066400000000000000000000652141262102574200205010ustar00rootroot00000000000000/* * Copyright (C) 2014 SUSE. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. * * Authors: Mark Fasheh */ #include #include #include #include "kerncompat.h" #include "radix-tree.h" #include "ctree.h" #include "disk-io.h" #include "print-tree.h" #include "utils.h" #include "ulist.h" #include "rbtree-utils.h" #include "qgroup-verify.h" /*#define QGROUP_VERIFY_DEBUG*/ static unsigned long tot_extents_scanned = 0; static void add_bytes(u64 root_objectid, u64 num_bytes, int exclusive); struct qgroup_count { u64 qgroupid; int subvol_exists; struct btrfs_disk_key key; struct btrfs_qgroup_info_item diskinfo; struct btrfs_qgroup_info_item info; struct rb_node rb_node; }; struct counts_tree { struct rb_root root; unsigned int num_groups; } counts = { .root = RB_ROOT }; struct rb_root by_bytenr = RB_ROOT; /* * List of interior tree blocks. We walk this list after loading the * extent tree to resolve implied refs. For each interior node we'll * place a shared ref in the ref tree against each child object. This * allows the shared ref resolving code to do the actual work later of * finding roots to account against. * * An implied ref is when a tree block has refs on it that may not * exist in any of its child nodes. Even though the refs might not * exist further down the tree, the fact that our interior node has a * ref means we need to account anything below it to all its roots. */ struct ulist *tree_blocks = NULL; /* unode->val = bytenr, ->aux * = tree_block pointer */ struct tree_block { int level; u64 num_bytes; }; struct ref { u64 bytenr; u64 num_bytes; u64 parent; u64 root; struct rb_node bytenr_node; }; #ifdef QGROUP_VERIFY_DEBUG static void print_ref(struct ref *ref) { printf("bytenr: %llu\t\tnum_bytes: %llu\t\t parent: %llu\t\t" "root: %llu\n", ref->bytenr, ref->num_bytes, ref->parent, ref->root); } static void print_all_refs(void) { unsigned long count = 0; struct ref *ref; struct rb_node *node; node = rb_first(&by_bytenr); while (node) { ref = rb_entry(node, struct ref, bytenr_node); print_ref(ref); count++; node = rb_next(node); } printf("%lu extents scanned with %lu refs in total.\n", tot_extents_scanned, count); } #endif /* * Store by bytenr in rbtree * * The tree is sorted in ascending order by bytenr, then parent, then * root. Since full refs have a parent == 0, those will come before * shared refs. */ static int compare_ref(struct ref *orig, u64 bytenr, u64 root, u64 parent) { if (bytenr < orig->bytenr) return -1; if (bytenr > orig->bytenr) return 1; if (parent < orig->parent) return -1; if (parent > orig->parent) return 1; if (root < orig->root) return -1; if (root > orig->root) return 1; return 0; } /* * insert a new ref into the tree. returns the existing ref entry * if one is already there. */ static struct ref *insert_ref(struct ref *ref) { int ret; struct rb_node **p = &by_bytenr.rb_node; struct rb_node *parent = NULL; struct ref *curr; while (*p) { parent = *p; curr = rb_entry(parent, struct ref, bytenr_node); ret = compare_ref(curr, ref->bytenr, ref->root, ref->parent); if (ret < 0) p = &(*p)->rb_left; else if (ret > 0) p = &(*p)->rb_right; else return curr; } rb_link_node(&ref->bytenr_node, parent, p); rb_insert_color(&ref->bytenr_node, &by_bytenr); return ref; } /* * Partial search, returns the first ref with matching bytenr. Caller * can walk forward from there. * * Leftmost refs will be full refs - this is used to our advantage * when resolving roots. */ static struct ref *find_ref_bytenr(u64 bytenr) { struct rb_node *n = by_bytenr.rb_node; struct ref *ref; while (n) { ref = rb_entry(n, struct ref, bytenr_node); if (bytenr < ref->bytenr) n = n->rb_left; else if (bytenr > ref->bytenr) n = n->rb_right; else { /* Walk to the left to find the first item */ struct rb_node *node_left = rb_prev(&ref->bytenr_node); struct ref *ref_left; while (node_left) { ref_left = rb_entry(node_left, struct ref, bytenr_node); if (ref_left->bytenr != ref->bytenr) break; ref = ref_left; node_left = rb_prev(node_left); } return ref; } } return NULL; } static struct ref *find_ref(u64 bytenr, u64 root, u64 parent) { struct rb_node *n = by_bytenr.rb_node; struct ref *ref; int ret; while (n) { ref = rb_entry(n, struct ref, bytenr_node); ret = compare_ref(ref, bytenr, root, parent); if (ret < 0) n = n->rb_left; else if (ret > 0) n = n->rb_right; else return ref; } return NULL; } static struct ref *alloc_ref(u64 bytenr, u64 root, u64 parent, u64 num_bytes) { struct ref *ref = find_ref(bytenr, root, parent); BUG_ON(parent && root); if (ref == NULL) { ref = calloc(1, sizeof(*ref)); if (ref) { ref->bytenr = bytenr; ref->root = root; ref->parent = parent; ref->num_bytes = num_bytes; insert_ref(ref); } } return ref; } static void free_ref_node(struct rb_node *node) { struct ref *ref = rb_entry(node, struct ref, bytenr_node); free(ref); } FREE_RB_BASED_TREE(ref, free_ref_node); /* * Resolves all the possible roots for the ref at parent. */ static void find_parent_roots(struct ulist *roots, u64 parent) { struct ref *ref; struct rb_node *node; /* * Search the rbtree for the first ref with bytenr == parent. * Walk forward so long as bytenr == parent, adding resolved root ids. * For each unresolved root, we recurse */ ref = find_ref_bytenr(parent); node = &ref->bytenr_node; BUG_ON(ref == NULL); BUG_ON(ref->bytenr != parent); { /* * Random sanity check, are we actually getting the * leftmost node? */ struct rb_node *prev_node = rb_prev(&ref->bytenr_node); struct ref *prev; if (prev_node) { prev = rb_entry(prev_node, struct ref, bytenr_node); BUG_ON(prev->bytenr == parent); } } do { if (ref->root) ulist_add(roots, ref->root, 0, 0); else find_parent_roots(roots, ref->parent); node = rb_next(node); if (node) ref = rb_entry(node, struct ref, bytenr_node); } while (node && ref->bytenr == parent); } static void print_subvol_info(u64 subvolid, u64 bytenr, u64 num_bytes, struct ulist *roots); /* * Account each ref. Walk the refs, for each set of refs in a * given bytenr: * * - add the roots for direct refs to the ref roots ulist * * - resolve all possible roots for shared refs, insert each * of those into ref_roots ulist (this is a recursive process) * * - Walk ref_roots ulist, adding extent bytes to each qgroup count that * cooresponds to a found root. */ static void account_all_refs(int do_qgroups, u64 search_subvol) { int exclusive; struct ref *ref; struct rb_node *node; u64 bytenr, num_bytes; struct ulist *roots = ulist_alloc(0); struct ulist_iterator uiter; struct ulist_node *unode; node = rb_first(&by_bytenr); while (node) { ulist_reinit(roots); ref = rb_entry(node, struct ref, bytenr_node); /* * Walk forward through the list of refs for this * bytenr, adding roots to our ulist. If it's a full * ref, then we have the easy case. Otherwise we need * to search for roots. */ bytenr = ref->bytenr; num_bytes = ref->num_bytes; do { BUG_ON(ref->bytenr != bytenr); BUG_ON(ref->num_bytes != num_bytes); if (ref->root) ulist_add(roots, ref->root, 0, 0); else find_parent_roots(roots, ref->parent); /* * When we leave this inner loop, node is set * to next in our tree and will be turned into * a ref object up top */ node = rb_next(node); if (node) ref = rb_entry(node, struct ref, bytenr_node); } while (node && ref->bytenr == bytenr); /* * Now that we have all roots, we can properly account * this extent against the corresponding qgroups. */ if (roots->nnodes == 1) exclusive = 1; else exclusive = 0; if (search_subvol) print_subvol_info(search_subvol, bytenr, num_bytes, roots); ULIST_ITER_INIT(&uiter); while ((unode = ulist_next(roots, &uiter))) { BUG_ON(unode->val == 0ULL); /* We only want to account fs trees */ if (is_fstree(unode->val) && do_qgroups) add_bytes(unode->val, num_bytes, exclusive); } } ulist_free(roots); } static u64 resolve_one_root(u64 bytenr) { struct ref *ref = find_ref_bytenr(bytenr); BUG_ON(ref == NULL); if (ref->root) return ref->root; return resolve_one_root(ref->parent); } static inline struct tree_block *unode_tree_block(struct ulist_node *unode) { return u64_to_ptr(unode->aux); } static inline u64 unode_bytenr(struct ulist_node *unode) { return unode->val; } static int alloc_tree_block(u64 bytenr, u64 num_bytes, int level) { struct tree_block *block = calloc(1, sizeof(*block)); if (block) { block->num_bytes = num_bytes; block->level = level; if (ulist_add(tree_blocks, bytenr, ptr_to_u64(block), 0) >= 0) return 0; free(block); } return -ENOMEM; } static void free_tree_blocks(void) { struct ulist_iterator uiter; struct ulist_node *unode; if (!tree_blocks) return; ULIST_ITER_INIT(&uiter); while ((unode = ulist_next(tree_blocks, &uiter))) free(unode_tree_block(unode)); ulist_free(tree_blocks); tree_blocks = NULL; } #ifdef QGROUP_VERIFY_DEBUG static void print_tree_block(u64 bytenr, struct tree_block *block) { struct ref *ref; struct rb_node *node; printf("tree block: %llu\t\tlevel: %d\n", (unsigned long long)bytenr, block->level); ref = find_ref_bytenr(bytenr); node = &ref->bytenr_node; do { print_ref(ref); node = rb_next(node); if (node) ref = rb_entry(node, struct ref, bytenr_node); } while (node && ref->bytenr == bytenr); printf("\n"); } static void print_all_tree_blocks(void) { struct ulist_iterator uiter; struct ulist_node *unode; if (!tree_blocks) return; printf("Listing all found interior tree nodes:\n"); ULIST_ITER_INIT(&uiter); while ((unode = ulist_next(tree_blocks, &uiter))) print_tree_block(unode_bytenr(unode), unode_tree_block(unode)); } #endif static int add_refs_for_leaf_items(struct extent_buffer *eb, u64 ref_parent) { int nr, i; int extent_type; u64 bytenr, num_bytes; struct btrfs_key key; struct btrfs_disk_key disk_key; struct btrfs_file_extent_item *fi; nr = btrfs_header_nritems(eb); for (i = 0; i < nr; i++) { btrfs_item_key(eb, &disk_key, i); btrfs_disk_key_to_cpu(&key, &disk_key); if (key.type != BTRFS_EXTENT_DATA_KEY) continue; fi = btrfs_item_ptr(eb, i, struct btrfs_file_extent_item); /* filter out: inline, disk_bytenr == 0, compressed? * not if we can avoid it */ extent_type = btrfs_file_extent_type(eb, fi); if (extent_type == BTRFS_FILE_EXTENT_INLINE) continue; bytenr = btrfs_file_extent_disk_bytenr(eb, fi); if (!bytenr) continue; num_bytes = btrfs_file_extent_disk_num_bytes(eb, fi); if (alloc_ref(bytenr, 0, ref_parent, num_bytes) == NULL) return ENOMEM; } return 0; } static int travel_tree(struct btrfs_fs_info *info, struct btrfs_root *root, u64 bytenr, u64 num_bytes, u64 ref_parent) { int ret, nr, i; struct extent_buffer *eb; u64 new_bytenr; u64 new_num_bytes; // printf("travel_tree: bytenr: %llu\tnum_bytes: %llu\tref_parent: %llu\n", // bytenr, num_bytes, ref_parent); eb = read_tree_block(root, bytenr, num_bytes, 0); if (!eb) return -EIO; ret = 0; /* Don't add a ref for our starting tree block to itself */ if (bytenr != ref_parent) { if (alloc_ref(bytenr, 0, ref_parent, num_bytes) == NULL) return ENOMEM; } if (btrfs_is_leaf(eb)) { ret = add_refs_for_leaf_items(eb, ref_parent); goto out; } /* * Interior nodes are tuples of (key, bytenr) where key is the * leftmost key in the tree block pointed to by bytenr. We * don't have to care about key here, just follow the bytenr * pointer. */ nr = btrfs_header_nritems(eb); for (i = 0; i < nr; i++) { new_bytenr = btrfs_node_blockptr(eb, i); new_num_bytes = btrfs_level_size(root, btrfs_header_level(eb) - 1); ret = travel_tree(info, root, new_bytenr, new_num_bytes, ref_parent); } out: free_extent_buffer(eb); return ret; } static int add_refs_for_implied(struct btrfs_fs_info *info, u64 bytenr, struct tree_block *block) { int ret; u64 root_id = resolve_one_root(bytenr); struct btrfs_root *root; struct btrfs_key key; key.objectid = root_id; key.type = BTRFS_ROOT_ITEM_KEY; key.offset = (u64)-1; /* * XXX: Don't free the root object as we don't know whether it * came off our fs_info struct or not. */ root = btrfs_read_fs_root(info, &key); if (!root || IS_ERR(root)) return ENOENT; ret = travel_tree(info, root, bytenr, block->num_bytes, bytenr); if (ret) return ret; return 0; } /* * Place shared refs in the ref tree for each child of an interior tree node. */ static int map_implied_refs(struct btrfs_fs_info *info) { int ret = 0; struct ulist_iterator uiter; struct ulist_node *unode; ULIST_ITER_INIT(&uiter); while ((unode = ulist_next(tree_blocks, &uiter))) { ret = add_refs_for_implied(info, unode_bytenr(unode), unode_tree_block(unode)); if (ret) goto out; } out: return ret; } /* * insert a new root into the tree. returns the existing root entry * if one is already there. qgroupid is used * as the key */ static int insert_count(struct qgroup_count *qc) { struct rb_node **p = &counts.root.rb_node; struct rb_node *parent = NULL; struct qgroup_count *curr; while (*p) { parent = *p; curr = rb_entry(parent, struct qgroup_count, rb_node); if (qc->qgroupid < curr->qgroupid) p = &(*p)->rb_left; else if (qc->qgroupid > curr->qgroupid) p = &(*p)->rb_right; else return EEXIST; } counts.num_groups++; rb_link_node(&qc->rb_node, parent, p); rb_insert_color(&qc->rb_node, &counts.root); return 0; } static struct qgroup_count *find_count(u64 qgroupid) { struct rb_node *n = counts.root.rb_node; struct qgroup_count *count; while (n) { count = rb_entry(n, struct qgroup_count, rb_node); if (qgroupid < count->qgroupid) n = n->rb_left; else if (qgroupid > count->qgroupid) n = n->rb_right; else return count; } return NULL; } static struct qgroup_count *alloc_count(struct btrfs_disk_key *key, struct extent_buffer *leaf, struct btrfs_qgroup_info_item *disk) { struct qgroup_count *c = calloc(1, sizeof(*c)); struct btrfs_qgroup_info_item *item; if (c) { c->qgroupid = btrfs_disk_key_offset(key); c->key = *key; item = &c->diskinfo; item->generation = btrfs_qgroup_info_generation(leaf, disk); item->referenced = btrfs_qgroup_info_referenced(leaf, disk); item->referenced_compressed = btrfs_qgroup_info_referenced_compressed(leaf, disk); item->exclusive = btrfs_qgroup_info_exclusive(leaf, disk); item->exclusive_compressed = btrfs_qgroup_info_exclusive_compressed(leaf, disk); if (insert_count(c)) { free(c); c = NULL; } } return c; } static void add_bytes(u64 root_objectid, u64 num_bytes, int exclusive) { struct qgroup_count *count = find_count(root_objectid); struct btrfs_qgroup_info_item *qg; BUG_ON(num_bytes < 4096); /* Random sanity check. */ if (!count) return; qg = &count->info; qg->referenced += num_bytes; /* * count of compressed bytes is unimplemented, so we do the * same as kernel. */ qg->referenced_compressed += num_bytes; if (exclusive) { qg->exclusive += num_bytes; qg->exclusive_compressed += num_bytes; } } static int load_quota_info(struct btrfs_fs_info *info) { int ret; struct btrfs_root *root = info->quota_root; struct btrfs_root *tmproot; struct btrfs_path path; struct btrfs_key key; struct btrfs_key root_key; struct btrfs_disk_key disk_key; struct extent_buffer *leaf; struct btrfs_qgroup_info_item *item; struct qgroup_count *count; int i, nr; btrfs_init_path(&path); key.offset = 0; key.objectid = 0; key.type = 0; ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0); if (ret < 0) { fprintf(stderr, "ERROR: Couldn't search slot: %d\n", ret); goto out; } while (1) { leaf = path.nodes[0]; nr = btrfs_header_nritems(leaf); for(i = 0; i < nr; i++) { btrfs_item_key(leaf, &disk_key, i); btrfs_disk_key_to_cpu(&key, &disk_key); if (key.type == BTRFS_QGROUP_RELATION_KEY) printf("Ignoring qgroup relation key %llu\n", key.objectid); /* * Ignore: BTRFS_QGROUP_STATUS_KEY, * BTRFS_QGROUP_LIMIT_KEY, BTRFS_QGROUP_RELATION_KEY */ if (key.type != BTRFS_QGROUP_INFO_KEY) continue; item = btrfs_item_ptr(leaf, i, struct btrfs_qgroup_info_item); count = alloc_count(&disk_key, leaf, item); if (!count) { ret = ENOMEM; fprintf(stderr, "ERROR: out of memory\n"); goto out; } root_key.objectid = key.offset; root_key.type = BTRFS_ROOT_ITEM_KEY; root_key.offset = (u64)-1; tmproot = btrfs_read_fs_root_no_cache(info, &root_key); if (tmproot && !IS_ERR(tmproot)) { count->subvol_exists = 1; free(tmproot); } } ret = btrfs_next_leaf(root, &path); if (ret != 0) break; } ret = 0; btrfs_release_path(&path); out: return ret; } static int add_inline_refs(struct btrfs_fs_info *info, struct extent_buffer *ei_leaf, int slot, u64 bytenr, u64 num_bytes, int meta_item) { struct btrfs_extent_item *ei; struct btrfs_extent_inline_ref *iref; struct btrfs_extent_data_ref *dref; u64 flags, root_obj, offset, parent; u32 item_size = btrfs_item_size_nr(ei_leaf, slot); int type; unsigned long end; unsigned long ptr; ei = btrfs_item_ptr(ei_leaf, slot, struct btrfs_extent_item); flags = btrfs_extent_flags(ei_leaf, ei); if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK && !meta_item) { struct btrfs_tree_block_info *tbinfo; tbinfo = (struct btrfs_tree_block_info *)(ei + 1); iref = (struct btrfs_extent_inline_ref *)(tbinfo + 1); } else { iref = (struct btrfs_extent_inline_ref *)(ei + 1); } ptr = (unsigned long)iref; end = (unsigned long)ei + item_size; while (ptr < end) { iref = (struct btrfs_extent_inline_ref *)ptr; parent = root_obj = 0; offset = btrfs_extent_inline_ref_offset(ei_leaf, iref); type = btrfs_extent_inline_ref_type(ei_leaf, iref); switch (type) { case BTRFS_TREE_BLOCK_REF_KEY: root_obj = offset; break; case BTRFS_EXTENT_DATA_REF_KEY: dref = (struct btrfs_extent_data_ref *)(&iref->offset); root_obj = btrfs_extent_data_ref_root(ei_leaf, dref); break; case BTRFS_SHARED_DATA_REF_KEY: case BTRFS_SHARED_BLOCK_REF_KEY: parent = offset; break; default: return 1; } if (alloc_ref(bytenr, root_obj, parent, num_bytes) == NULL) return ENOMEM; ptr += btrfs_extent_inline_ref_size(type); } return 0; } static int add_keyed_ref(struct btrfs_fs_info *info, struct btrfs_key *key, struct extent_buffer *leaf, int slot, u64 bytenr, u64 num_bytes) { u64 root_obj = 0, parent = 0; struct btrfs_extent_data_ref *dref; switch(key->type) { case BTRFS_TREE_BLOCK_REF_KEY: root_obj = key->offset; break; case BTRFS_EXTENT_DATA_REF_KEY: dref = btrfs_item_ptr(leaf, slot, struct btrfs_extent_data_ref); root_obj = btrfs_extent_data_ref_root(leaf, dref); break; case BTRFS_SHARED_DATA_REF_KEY: case BTRFS_SHARED_BLOCK_REF_KEY: parent = key->offset; break; default: return 1; } if (alloc_ref(bytenr, root_obj, parent, num_bytes) == NULL) return ENOMEM; return 0; } /* * return value of 0 indicates leaf or not meta data. The code that * calls this does not need to make a distinction between the two as * it is only concerned with intermediate blocks which will always * have level > 0. */ static int get_tree_block_level(struct btrfs_key *key, struct extent_buffer *ei_leaf, int slot) { int level = 0; int meta_key = key->type == BTRFS_METADATA_ITEM_KEY; u64 flags; struct btrfs_extent_item *ei; ei = btrfs_item_ptr(ei_leaf, slot, struct btrfs_extent_item); flags = btrfs_extent_flags(ei_leaf, ei); if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK && !meta_key) { struct btrfs_tree_block_info *tbinfo; tbinfo = (struct btrfs_tree_block_info *)(ei + 1); level = btrfs_tree_block_level(ei_leaf, tbinfo); } else if (meta_key) { /* skinny metadata */ level = (int)key->offset; } return level; } /* * Walk the extent tree, allocating a ref item for every ref and * storing it in the bytenr tree. */ static int scan_extents(struct btrfs_fs_info *info, u64 start, u64 end) { int ret, i, nr, level; struct btrfs_root *root = info->extent_root; struct btrfs_key key; struct btrfs_path path; struct btrfs_disk_key disk_key; struct extent_buffer *leaf; u64 bytenr = 0, num_bytes = 0; btrfs_init_path(&path); key.objectid = start; key.type = 0; key.offset = 0; ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0); if (ret < 0) { fprintf(stderr, "ERROR: Couldn't search slot: %d\n", ret); goto out; } path.reada = 1; while (1) { leaf = path.nodes[0]; nr = btrfs_header_nritems(leaf); for(i = 0; i < nr; i++) { btrfs_item_key(leaf, &disk_key, i); btrfs_disk_key_to_cpu(&key, &disk_key); if (key.objectid < start) continue; if (key.objectid > end) goto done; if (key.type == BTRFS_EXTENT_ITEM_KEY || key.type == BTRFS_METADATA_ITEM_KEY) { int meta = 0; tot_extents_scanned++; bytenr = key.objectid; num_bytes = key.offset; if (key.type == BTRFS_METADATA_ITEM_KEY) { num_bytes = info->extent_root->leafsize; meta = 1; } ret = add_inline_refs(info, leaf, i, bytenr, num_bytes, meta); if (ret) goto out; level = get_tree_block_level(&key, leaf, i); if (level) { if (alloc_tree_block(bytenr, num_bytes, level)) return ENOMEM; } continue; } if (key.type > BTRFS_SHARED_DATA_REF_KEY) continue; if (key.type < BTRFS_TREE_BLOCK_REF_KEY) continue; /* * Keyed refs should come after their extent * item in the tree. As a result, the value of * bytenr and num_bytes should be unchanged * from the above block that catches the * original extent item. */ BUG_ON(key.objectid != bytenr); ret = add_keyed_ref(info, &key, leaf, i, bytenr, num_bytes); if (ret) goto out; } ret = btrfs_next_leaf(root, &path); if (ret != 0) { if (ret < 0) { fprintf(stderr, "ERROR: Next leaf failed: %d\n", ret); goto out; } break; } } done: ret = 0; out: btrfs_release_path(&path); return ret; } static void print_fields(u64 bytes, u64 bytes_compressed, char *prefix, char *type) { printf("%s\t\t%s %llu %s compressed %llu\n", prefix, type, (unsigned long long)bytes, type, (unsigned long long)bytes_compressed); } static void print_fields_signed(long long bytes, long long bytes_compressed, char *prefix, char *type) { printf("%s\t\t%s %lld %s compressed %lld\n", prefix, type, bytes, type, bytes_compressed); } static void print_qgroup_difference(struct qgroup_count *count, int verbose) { int is_different; struct btrfs_qgroup_info_item *info = &count->info; struct btrfs_qgroup_info_item *disk = &count->diskinfo; long long excl_diff = info->exclusive - disk->exclusive; long long ref_diff = info->referenced - disk->referenced; is_different = excl_diff || ref_diff; if (verbose || (is_different && count->subvol_exists)) { printf("Counts for qgroup id: %llu %s\n", (unsigned long long)count->qgroupid, is_different ? "are different" : ""); print_fields(info->referenced, info->referenced_compressed, "our:", "referenced"); print_fields(disk->referenced, disk->referenced_compressed, "disk:", "referenced"); if (ref_diff) print_fields_signed(ref_diff, ref_diff, "diff:", "referenced"); print_fields(info->exclusive, info->exclusive_compressed, "our:", "exclusive"); print_fields(disk->exclusive, disk->exclusive_compressed, "disk:", "exclusive"); if (excl_diff) print_fields_signed(excl_diff, excl_diff, "diff:", "exclusive"); } } void print_qgroup_report(int all) { struct rb_node *node; struct qgroup_count *c; node = rb_first(&counts.root); while (node) { c = rb_entry(node, struct qgroup_count, rb_node); print_qgroup_difference(c, all); node = rb_next(node); } } int qgroup_verify_all(struct btrfs_fs_info *info) { int ret; if (!info->quota_enabled) return 0; tree_blocks = ulist_alloc(0); if (!tree_blocks) { fprintf(stderr, "ERROR: Out of memory while allocating ulist.\n"); return ENOMEM; } ret = load_quota_info(info); if (ret) { fprintf(stderr, "ERROR: Loading qgroups from disk: %d\n", ret); goto out; } /* * Put all extent refs into our rbtree */ ret = scan_extents(info, 0, ~0ULL); if (ret) { fprintf(stderr, "ERROR: while scanning extent tree: %d\n", ret); goto out; } ret = map_implied_refs(info); if (ret) { fprintf(stderr, "ERROR: while mapping refs: %d\n", ret); goto out; } account_all_refs(1, 0); out: /* * Don't free the qgroup count records as they will be walked * later via the print function. */ free_tree_blocks(); free_ref_tree(&by_bytenr); return ret; } static void __print_subvol_info(u64 bytenr, u64 num_bytes, struct ulist *roots) { int n = roots->nnodes; struct ulist_iterator uiter; struct ulist_node *unode; printf("%llu\t%llu\t%d\t", bytenr, num_bytes, n); ULIST_ITER_INIT(&uiter); while ((unode = ulist_next(roots, &uiter))) { printf("%llu ", unode->val); } printf("\n"); } static void print_subvol_info(u64 subvolid, u64 bytenr, u64 num_bytes, struct ulist *roots) { struct ulist_iterator uiter; struct ulist_node *unode; ULIST_ITER_INIT(&uiter); while ((unode = ulist_next(roots, &uiter))) { BUG_ON(unode->val == 0ULL); if (unode->val == subvolid) { __print_subvol_info(bytenr, num_bytes, roots); return; } } } int print_extent_state(struct btrfs_fs_info *info, u64 subvol) { int ret; tree_blocks = ulist_alloc(0); if (!tree_blocks) { fprintf(stderr, "ERROR: Out of memory while allocating ulist.\n"); return ENOMEM; } /* * Put all extent refs into our rbtree */ ret = scan_extents(info, 0, ~0ULL); if (ret) { fprintf(stderr, "ERROR: while scanning extent tree: %d\n", ret); goto out; } ret = map_implied_refs(info); if (ret) { fprintf(stderr, "ERROR: while mapping refs: %d\n", ret); goto out; } printf("Offset\t\tLen\tRoot Refs\tRoots\n"); account_all_refs(0, subvol); out: free_tree_blocks(); free_ref_tree(&by_bytenr); return ret; } partclone-0.2.86/src/btrfs/qgroup-verify.h000066400000000000000000000016761262102574200205100ustar00rootroot00000000000000/* * Copyright (C) 2014 SUSE. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. */ #ifndef _BTRFS_QGROUP_VERIFY_H #define _BTRFS_QGROUP_VERIFY_H int qgroup_verify_all(struct btrfs_fs_info *info); void print_qgroup_report(int all); int print_extent_state(struct btrfs_fs_info *info, u64 subvol); #endif /* _BTRFS_QGROUP_VERIFY_H */ partclone-0.2.86/src/btrfs/qgroup.c000066400000000000000000000751341262102574200172010ustar00rootroot00000000000000/* * Copyright (C) 2012 STRATO. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. */ #include "qgroup.h" #include #include "ctree.h" #include "ioctl.h" #define BTRFS_QGROUP_NFILTERS_INCREASE (2 * BTRFS_QGROUP_FILTER_MAX) #define BTRFS_QGROUP_NCOMPS_INCREASE (2 * BTRFS_QGROUP_COMP_MAX) struct qgroup_lookup { struct rb_root root; }; struct btrfs_qgroup { struct rb_node rb_node; struct rb_node sort_node; /* *all_parent_node is used to *filter a qgroup's all parent */ struct rb_node all_parent_node; u64 qgroupid; /* * info_item */ u64 generation; u64 rfer; /*referenced*/ u64 rfer_cmpr; /*referenced compressed*/ u64 excl; /*exclusive*/ u64 excl_cmpr; /*exclusive compressed*/ /* *limit_item */ u64 flags; /*which limits are set*/ u64 max_rfer; u64 max_excl; u64 rsv_rfer; u64 rsv_excl; /*qgroups this group is member of*/ struct list_head qgroups; /*qgroups that are members of this group*/ struct list_head members; }; /* * glue structure to represent the relations * between qgroups */ struct btrfs_qgroup_list { struct list_head next_qgroup; struct list_head next_member; struct btrfs_qgroup *qgroup; struct btrfs_qgroup *member; }; /* * qgroupid,rfer,excl default to set */ static struct { char *name; char *column_name; int need_print; int max_len; } btrfs_qgroup_columns[] = { { .name = "qgroupid", .column_name = "Qgroupid", .need_print = 1, .max_len = 8, }, { .name = "rfer", .column_name = "Rfer", .need_print = 1, .max_len = 4, }, { .name = "excl", .column_name = "Excl", .need_print = 1, .max_len = 4, }, { .name = "max_rfer", .column_name = "Max_rfer", .need_print = 0, .max_len = 8, }, { .name = "max_excl", .column_name = "Max_excl", .need_print = 0, .max_len = 8, }, { .name = "parent", .column_name = "Parent", .need_print = 0, .max_len = 7, }, { .name = "child", .column_name = "Child", .need_print = 0, .max_len = 5, }, { .name = NULL, .column_name = NULL, .need_print = 0, }, }; static btrfs_qgroup_filter_func all_filter_funcs[]; static btrfs_qgroup_comp_func all_comp_funcs[]; void btrfs_qgroup_setup_print_column(enum btrfs_qgroup_column_enum column) { int i; BUG_ON(column < 0 || column > BTRFS_QGROUP_ALL); if (column < BTRFS_QGROUP_ALL) { btrfs_qgroup_columns[column].need_print = 1; return; } for (i = 0; i < BTRFS_QGROUP_ALL; i++) btrfs_qgroup_columns[i].need_print = 1; } static int print_parent_column(struct btrfs_qgroup *qgroup) { struct btrfs_qgroup_list *list = NULL; int len = 0; list_for_each_entry(list, &qgroup->qgroups, next_qgroup) { len += printf("%llu/%llu", (list->qgroup)->qgroupid >> 48, ((1ll << 48) - 1) & (list->qgroup)->qgroupid); if (!list_is_last(&list->next_qgroup, &qgroup->qgroups)) len += printf(","); } if (list_empty(&qgroup->qgroups)) len += printf("---"); return len; } static int print_child_column(struct btrfs_qgroup *qgroup) { struct btrfs_qgroup_list *list = NULL; int len = 0; list_for_each_entry(list, &qgroup->members, next_member) { len += printf("%llu/%llu", (list->member)->qgroupid >> 48, ((1ll << 48) - 1) & (list->member)->qgroupid); if (!list_is_last(&list->next_member, &qgroup->members)) len += printf(","); } if (list_empty(&qgroup->members)) len += printf("---"); return len; } static void print_qgroup_column_add_blank(enum btrfs_qgroup_column_enum column, int len) { len = btrfs_qgroup_columns[column].max_len - len; while (len--) printf(" "); } static void print_qgroup_column(struct btrfs_qgroup *qgroup, enum btrfs_qgroup_column_enum column) { BUG_ON(column >= BTRFS_QGROUP_ALL || column < 0); int len; switch (column) { case BTRFS_QGROUP_QGROUPID: len = printf("%llu/%llu", qgroup->qgroupid >> 48, ((1ll << 48) - 1) & qgroup->qgroupid); print_qgroup_column_add_blank(BTRFS_QGROUP_QGROUPID, len); break; case BTRFS_QGROUP_RFER: len = printf("%llu", qgroup->rfer); print_qgroup_column_add_blank(BTRFS_QGROUP_RFER, len); break; case BTRFS_QGROUP_EXCL: len = printf("%llu", qgroup->excl); print_qgroup_column_add_blank(BTRFS_QGROUP_EXCL, len); break; case BTRFS_QGROUP_PARENT: len = print_parent_column(qgroup); print_qgroup_column_add_blank(BTRFS_QGROUP_PARENT, len); break; case BTRFS_QGROUP_MAX_RFER: len = printf("%llu", qgroup->max_rfer); print_qgroup_column_add_blank(BTRFS_QGROUP_MAX_RFER, len); break; case BTRFS_QGROUP_MAX_EXCL: len = printf("%llu", qgroup->max_excl); print_qgroup_column_add_blank(BTRFS_QGROUP_MAX_EXCL, len); break; case BTRFS_QGROUP_CHILD: len = print_child_column(qgroup); print_qgroup_column_add_blank(BTRFS_QGROUP_CHILD, len); break; default: break; } } static void print_single_qgroup_table(struct btrfs_qgroup *qgroup) { int i; for (i = 0; i < BTRFS_QGROUP_ALL; i++) { if (!btrfs_qgroup_columns[i].need_print) continue; print_qgroup_column(qgroup, i); if (i != BTRFS_QGROUP_CHILD) printf(" "); } printf("\n"); } static void print_table_head() { int i; int len; for (i = 0; i < BTRFS_QGROUP_ALL; i++) { if (!btrfs_qgroup_columns[i].need_print) continue; printf("%s", btrfs_qgroup_columns[i].name); len = btrfs_qgroup_columns[i].max_len - strlen(btrfs_qgroup_columns[i].name); while (len--) printf(" "); printf(" "); } printf("\n"); for (i = 0; i < BTRFS_QGROUP_ALL; i++) { if (!btrfs_qgroup_columns[i].need_print) continue; len = strlen(btrfs_qgroup_columns[i].name); while (len--) printf("-"); len = btrfs_qgroup_columns[i].max_len - strlen(btrfs_qgroup_columns[i].name); printf(" "); while (len--) printf(" "); } printf("\n"); } static void qgroup_lookup_init(struct qgroup_lookup *tree) { tree->root.rb_node = NULL; } static int comp_entry_with_qgroupid(struct btrfs_qgroup *entry1, struct btrfs_qgroup *entry2, int is_descending) { int ret; if (entry1->qgroupid > entry2->qgroupid) ret = 1; else if (entry1->qgroupid < entry2->qgroupid) ret = -1; else ret = 0; return is_descending ? -ret : ret; } static int comp_entry_with_rfer(struct btrfs_qgroup *entry1, struct btrfs_qgroup *entry2, int is_descending) { int ret; if (entry1->rfer > entry2->rfer) ret = 1; else if (entry1->rfer < entry2->rfer) ret = -1; else ret = 0; return is_descending ? -ret : ret; } static int comp_entry_with_excl(struct btrfs_qgroup *entry1, struct btrfs_qgroup *entry2, int is_descending) { int ret; if (entry1->excl > entry2->excl) ret = 1; else if (entry1->excl < entry2->excl) ret = -1; else ret = 0; return is_descending ? -ret : ret; } static int comp_entry_with_max_rfer(struct btrfs_qgroup *entry1, struct btrfs_qgroup *entry2, int is_descending) { int ret; if (entry1->max_rfer > entry2->max_rfer) ret = 1; else if (entry1->max_rfer < entry2->max_rfer) ret = -1; else ret = 0; return is_descending ? -ret : ret; } static int comp_entry_with_max_excl(struct btrfs_qgroup *entry1, struct btrfs_qgroup *entry2, int is_descending) { int ret; if (entry1->max_excl > entry2->max_excl) ret = 1; else if (entry1->max_excl < entry2->max_excl) ret = -1; else ret = 0; return is_descending ? -ret : ret; } static btrfs_qgroup_comp_func all_comp_funcs[] = { [BTRFS_QGROUP_COMP_QGROUPID] = comp_entry_with_qgroupid, [BTRFS_QGROUP_COMP_RFER] = comp_entry_with_rfer, [BTRFS_QGROUP_COMP_EXCL] = comp_entry_with_excl, [BTRFS_QGROUP_COMP_MAX_RFER] = comp_entry_with_max_rfer, [BTRFS_QGROUP_COMP_MAX_EXCL] = comp_entry_with_max_excl }; static char *all_sort_items[] = { [BTRFS_QGROUP_COMP_QGROUPID] = "qgroupid", [BTRFS_QGROUP_COMP_RFER] = "rfer", [BTRFS_QGROUP_COMP_EXCL] = "excl", [BTRFS_QGROUP_COMP_MAX_RFER] = "max_rfer", [BTRFS_QGROUP_COMP_MAX_EXCL] = "max_excl", [BTRFS_QGROUP_COMP_MAX] = NULL, }; static int btrfs_qgroup_get_sort_item(char *sort_name) { int i; for (i = 0; i < BTRFS_QGROUP_COMP_MAX; i++) { if (strcmp(sort_name, all_sort_items[i]) == 0) return i; } return -1; } struct btrfs_qgroup_comparer_set *btrfs_qgroup_alloc_comparer_set(void) { struct btrfs_qgroup_comparer_set *set; int size; size = sizeof(struct btrfs_qgroup_comparer_set) + BTRFS_QGROUP_NCOMPS_INCREASE * sizeof(struct btrfs_qgroup_comparer); set = malloc(size); if (!set) { fprintf(stderr, "memory allocation failed\n"); exit(1); } memset(set, 0, size); set->total = BTRFS_QGROUP_NCOMPS_INCREASE; return set; } void btrfs_qgroup_free_comparer_set(struct btrfs_qgroup_comparer_set *comp_set) { free(comp_set); } int btrfs_qgroup_setup_comparer(struct btrfs_qgroup_comparer_set **comp_set, enum btrfs_qgroup_comp_enum comparer, int is_descending) { struct btrfs_qgroup_comparer_set *set = *comp_set; int size; BUG_ON(!set); BUG_ON(comparer >= BTRFS_QGROUP_COMP_MAX); BUG_ON(set->ncomps > set->total); if (set->ncomps == set->total) { size = set->total + BTRFS_QGROUP_NCOMPS_INCREASE; size = sizeof(*set) + size * sizeof(struct btrfs_qgroup_comparer); set = realloc(set, size); if (!set) { fprintf(stderr, "memory allocation failed\n"); exit(1); } memset(&set->comps[set->total], 0, BTRFS_QGROUP_NCOMPS_INCREASE * sizeof(struct btrfs_qgroup_comparer)); set->total += BTRFS_QGROUP_NCOMPS_INCREASE; *comp_set = set; } BUG_ON(set->comps[set->ncomps].comp_func); set->comps[set->ncomps].comp_func = all_comp_funcs[comparer]; set->comps[set->ncomps].is_descending = is_descending; set->ncomps++; return 0; } static int sort_comp(struct btrfs_qgroup *entry1, struct btrfs_qgroup *entry2, struct btrfs_qgroup_comparer_set *set) { int qgroupid_compared = 0; int i, ret = 0; if (!set || !set->ncomps) goto comp_qgroupid; for (i = 0; i < set->ncomps; i++) { if (!set->comps[i].comp_func) break; ret = set->comps[i].comp_func(entry1, entry2, set->comps[i].is_descending); if (ret) return ret; if (set->comps[i].comp_func == comp_entry_with_qgroupid) qgroupid_compared = 1; } if (!qgroupid_compared) { comp_qgroupid: ret = comp_entry_with_qgroupid(entry1, entry2, 0); } return ret; } /* * insert a new root into the tree. returns the existing root entry * if one is already there. qgroupid is used * as the key */ static int qgroup_tree_insert(struct qgroup_lookup *root_tree, struct btrfs_qgroup *ins) { struct rb_node **p = &root_tree->root.rb_node; struct rb_node *parent = NULL; struct btrfs_qgroup *curr; int ret; while (*p) { parent = *p; curr = rb_entry(parent, struct btrfs_qgroup, rb_node); ret = comp_entry_with_qgroupid(ins, curr, 0); if (ret < 0) p = &(*p)->rb_left; else if (ret > 0) p = &(*p)->rb_right; else return -EEXIST; } rb_link_node(&ins->rb_node, parent, p); rb_insert_color(&ins->rb_node, &root_tree->root); return 0; } /* *find a given qgroupid in the tree. We return the smallest one, *rb_next can be used to move forward looking for more if required */ static struct btrfs_qgroup *qgroup_tree_search(struct qgroup_lookup *root_tree, u64 qgroupid) { struct rb_node *n = root_tree->root.rb_node; struct btrfs_qgroup *entry; struct btrfs_qgroup tmp; int ret; tmp.qgroupid = qgroupid; while (n) { entry = rb_entry(n, struct btrfs_qgroup, rb_node); ret = comp_entry_with_qgroupid(&tmp, entry, 0); if (ret < 0) n = n->rb_left; else if (ret > 0) n = n->rb_right; else return entry; } return NULL; } static int update_qgroup(struct qgroup_lookup *qgroup_lookup, u64 qgroupid, u64 generation, u64 rfer, u64 rfer_cmpr, u64 excl, u64 excl_cmpr, u64 flags, u64 max_rfer, u64 max_excl, u64 rsv_rfer, u64 rsv_excl, struct btrfs_qgroup *pa, struct btrfs_qgroup *child) { struct btrfs_qgroup *bq; struct btrfs_qgroup_list *list; bq = qgroup_tree_search(qgroup_lookup, qgroupid); if (!bq || bq->qgroupid != qgroupid) return -ENOENT; if (generation) bq->generation = generation; if (rfer) bq->rfer = rfer; if (rfer_cmpr) bq->rfer_cmpr = rfer_cmpr; if (excl) bq->excl = excl; if (excl_cmpr) bq->excl_cmpr = excl_cmpr; if (flags) bq->flags = flags; if (max_rfer) bq->max_rfer = max_rfer; if (max_excl) bq->max_excl = max_excl; if (rsv_rfer) bq->rsv_rfer = rsv_rfer; if (pa && child) { list = malloc(sizeof(*list)); if (!list) { fprintf(stderr, "memory allocation failed\n"); exit(1); } list->qgroup = pa; list->member = child; list_add_tail(&list->next_qgroup, &child->qgroups); list_add_tail(&list->next_member, &pa->members); } return 0; } static int add_qgroup(struct qgroup_lookup *qgroup_lookup, u64 qgroupid, u64 generation, u64 rfer, u64 rfer_cmpr, u64 excl, u64 excl_cmpr, u64 flags, u64 max_rfer, u64 max_excl, u64 rsv_rfer, u64 rsv_excl, struct btrfs_qgroup *parent, struct btrfs_qgroup *child) { struct btrfs_qgroup *bq; struct btrfs_qgroup_list *list; int ret; ret = update_qgroup(qgroup_lookup, qgroupid, generation, rfer, rfer_cmpr, excl, excl_cmpr, flags, max_rfer, max_excl, rsv_rfer, rsv_excl, parent, child); if (!ret) return 0; bq = malloc(sizeof(*bq)); if (!bq) { printf("memory allocation failed\n"); exit(1); } memset(bq, 0, sizeof(*bq)); if (qgroupid) { bq->qgroupid = qgroupid; INIT_LIST_HEAD(&bq->qgroups); INIT_LIST_HEAD(&bq->members); } if (generation) bq->generation = generation; if (rfer) bq->rfer = rfer; if (rfer_cmpr) bq->rfer_cmpr = rfer_cmpr; if (excl) bq->excl = excl; if (excl_cmpr) bq->excl_cmpr = excl_cmpr; if (flags) bq->flags = flags; if (max_rfer) bq->max_rfer = max_rfer; if (max_excl) bq->max_excl = max_excl; if (rsv_rfer) bq->rsv_rfer = rsv_rfer; if (parent && child) { list = malloc(sizeof(*list)); if (!list) { fprintf(stderr, "memory allocation failed\n"); exit(1); } list->qgroup = parent; list->member = child; list_add_tail(&list->next_qgroup, &child->qgroups); list_add_tail(&list->next_member, &parent->members); } ret = qgroup_tree_insert(qgroup_lookup, bq); if (ret) { printf("failed to insert tree %llu\n", bq->qgroupid); exit(1); } return ret; } static void __free_btrfs_qgroup(struct btrfs_qgroup *bq) { struct btrfs_qgroup_list *list; while (!list_empty(&bq->qgroups)) { list = list_entry((&bq->qgroups)->next, struct btrfs_qgroup_list, next_qgroup); list_del(&list->next_qgroup); list_del(&list->next_member); free(list); } while (!list_empty(&bq->members)) { list = list_entry((&bq->members)->next, struct btrfs_qgroup_list, next_member); list_del(&list->next_qgroup); list_del(&list->next_member); free(list); } free(bq); } static void __free_all_qgroups(struct qgroup_lookup *root_tree) { struct btrfs_qgroup *entry; struct rb_node *n; n = rb_first(&root_tree->root); while (n) { entry = rb_entry(n, struct btrfs_qgroup, rb_node); rb_erase(n, &root_tree->root); __free_btrfs_qgroup(entry); n = rb_first(&root_tree->root); } } static int filter_all_parent_insert(struct qgroup_lookup *sort_tree, struct btrfs_qgroup *bq) { struct rb_node **p = &sort_tree->root.rb_node; struct rb_node *parent = NULL; struct btrfs_qgroup *curr; int ret; while (*p) { parent = *p; curr = rb_entry(parent, struct btrfs_qgroup, all_parent_node); ret = comp_entry_with_qgroupid(bq, curr, 0); if (ret < 0) p = &(*p)->rb_left; else if (ret > 0) p = &(*p)->rb_right; else return -EEXIST; } rb_link_node(&bq->all_parent_node, parent, p); rb_insert_color(&bq->all_parent_node, &sort_tree->root); return 0; } static int filter_by_parent(struct btrfs_qgroup *bq, u64 data) { struct btrfs_qgroup *qgroup = (struct btrfs_qgroup *)(unsigned long)data; if (data == 0) return 0; if (qgroup->qgroupid == bq->qgroupid) return 1; return 0; } static int filter_by_all_parent(struct btrfs_qgroup *bq, u64 data) { struct qgroup_lookup lookup; struct qgroup_lookup *ql = &lookup; struct btrfs_qgroup_list *list; struct rb_node *n; struct btrfs_qgroup *qgroup = (struct btrfs_qgroup *)(unsigned long)data; if (data == 0) return 0; if (bq->qgroupid == qgroup->qgroupid) return 1; qgroup_lookup_init(ql); filter_all_parent_insert(ql, qgroup); n = rb_first(&ql->root); while (n) { qgroup = rb_entry(n, struct btrfs_qgroup, all_parent_node); if (!list_empty(&qgroup->qgroups)) { list_for_each_entry(list, &qgroup->qgroups, next_qgroup) { if ((list->qgroup)->qgroupid == bq->qgroupid) return 1; filter_all_parent_insert(ql, list->qgroup); } } rb_erase(n, &ql->root); n = rb_first(&ql->root); } return 0; } static btrfs_qgroup_filter_func all_filter_funcs[] = { [BTRFS_QGROUP_FILTER_PARENT] = filter_by_parent, [BTRFS_QGROUP_FILTER_ALL_PARENT] = filter_by_all_parent, }; struct btrfs_qgroup_filter_set *btrfs_qgroup_alloc_filter_set(void) { struct btrfs_qgroup_filter_set *set; int size; size = sizeof(struct btrfs_qgroup_filter_set) + BTRFS_QGROUP_NFILTERS_INCREASE * sizeof(struct btrfs_qgroup_filter); set = malloc(size); if (!set) { fprintf(stderr, "memory allocation failed\n"); exit(1); } memset(set, 0, size); set->total = BTRFS_QGROUP_NFILTERS_INCREASE; return set; } void btrfs_qgroup_free_filter_set(struct btrfs_qgroup_filter_set *filter_set) { free(filter_set); } int btrfs_qgroup_setup_filter(struct btrfs_qgroup_filter_set **filter_set, enum btrfs_qgroup_filter_enum filter, u64 data) { struct btrfs_qgroup_filter_set *set = *filter_set; int size; BUG_ON(!set); BUG_ON(filter >= BTRFS_QGROUP_FILTER_MAX); BUG_ON(set->nfilters > set->total); if (set->nfilters == set->total) { size = set->total + BTRFS_QGROUP_NFILTERS_INCREASE; size = sizeof(*set) + size * sizeof(struct btrfs_qgroup_filter); set = realloc(set, size); if (!set) { fprintf(stderr, "memory allocation failed\n"); exit(1); } memset(&set->filters[set->total], 0, BTRFS_QGROUP_NFILTERS_INCREASE * sizeof(struct btrfs_qgroup_filter)); set->total += BTRFS_QGROUP_NFILTERS_INCREASE; *filter_set = set; } BUG_ON(set->filters[set->nfilters].filter_func); set->filters[set->nfilters].filter_func = all_filter_funcs[filter]; set->filters[set->nfilters].data = data; set->nfilters++; return 0; } static int filter_qgroup(struct btrfs_qgroup *bq, struct btrfs_qgroup_filter_set *set) { int i, ret; if (!set || !set->nfilters) return 1; for (i = 0; i < set->nfilters; i++) { if (!set->filters[i].filter_func) break; ret = set->filters[i].filter_func(bq, set->filters[i].data); if (!ret) return 0; } return 1; } static void pre_process_filter_set(struct qgroup_lookup *lookup, struct btrfs_qgroup_filter_set *set) { int i; struct btrfs_qgroup *qgroup_for_filter = NULL; for (i = 0; i < set->nfilters; i++) { if (set->filters[i].filter_func == filter_by_all_parent || set->filters[i].filter_func == filter_by_parent) { qgroup_for_filter = qgroup_tree_search(lookup, set->filters[i].data); set->filters[i].data = (u64)(unsigned long)qgroup_for_filter; } } } static int sort_tree_insert(struct qgroup_lookup *sort_tree, struct btrfs_qgroup *bq, struct btrfs_qgroup_comparer_set *comp_set) { struct rb_node **p = &sort_tree->root.rb_node; struct rb_node *parent = NULL; struct btrfs_qgroup *curr; int ret; while (*p) { parent = *p; curr = rb_entry(parent, struct btrfs_qgroup, sort_node); ret = sort_comp(bq, curr, comp_set); if (ret < 0) p = &(*p)->rb_left; else if (ret > 0) p = &(*p)->rb_right; else return -EEXIST; } rb_link_node(&bq->sort_node, parent, p); rb_insert_color(&bq->sort_node, &sort_tree->root); return 0; } static void __update_columns_max_len(struct btrfs_qgroup *bq, enum btrfs_qgroup_column_enum column) { BUG_ON(column >= BTRFS_QGROUP_ALL || column < 0); struct btrfs_qgroup_list *list = NULL; char tmp[100]; int len; switch (column) { case BTRFS_QGROUP_QGROUPID: sprintf(tmp, "%llu/%llu", (bq->qgroupid >> 48), bq->qgroupid & ((1ll << 48) - 1)); len = strlen(tmp); if (btrfs_qgroup_columns[column].max_len < len) btrfs_qgroup_columns[column].max_len = len; break; case BTRFS_QGROUP_RFER: sprintf(tmp, "%llu", bq->rfer); len = strlen(tmp); if (btrfs_qgroup_columns[column].max_len < len) btrfs_qgroup_columns[column].max_len = len; break; case BTRFS_QGROUP_EXCL: sprintf(tmp, "%llu", bq->excl); len = strlen(tmp); if (btrfs_qgroup_columns[column].max_len < len) btrfs_qgroup_columns[column].max_len = len; break; case BTRFS_QGROUP_MAX_RFER: sprintf(tmp, "%llu", bq->max_rfer); len = strlen(tmp); if (btrfs_qgroup_columns[column].max_len < len) btrfs_qgroup_columns[column].max_len = len; break; case BTRFS_QGROUP_MAX_EXCL: sprintf(tmp, "%llu", bq->max_excl); len = strlen(tmp); if (btrfs_qgroup_columns[column].max_len < len) btrfs_qgroup_columns[column].max_len = len; break; case BTRFS_QGROUP_PARENT: len = 0; list_for_each_entry(list, &bq->qgroups, next_qgroup) { len += sprintf(tmp, "%llu/%llu", (list->qgroup)->qgroupid >> 48, ((1ll << 48) - 1) & (list->qgroup)->qgroupid); if (!list_is_last(&list->next_qgroup, &bq->qgroups)) len += 1; } if (btrfs_qgroup_columns[column].max_len < len) btrfs_qgroup_columns[column].max_len = len; break; case BTRFS_QGROUP_CHILD: len = 0; list_for_each_entry(list, &bq->members, next_member) { len += sprintf(tmp, "%llu/%llu", (list->member)->qgroupid >> 48, ((1ll << 48) - 1) & (list->member)->qgroupid); if (!list_is_last(&list->next_member, &bq->members)) len += 1; } if (btrfs_qgroup_columns[column].max_len < len) btrfs_qgroup_columns[column].max_len = len; break; default: break; } } static void update_columns_max_len(struct btrfs_qgroup *bq) { int i; for (i = 0; i < BTRFS_QGROUP_ALL; i++) { if (!btrfs_qgroup_columns[i].need_print) continue; __update_columns_max_len(bq, i); } } static void __filter_and_sort_qgroups(struct qgroup_lookup *all_qgroups, struct qgroup_lookup *sort_tree, struct btrfs_qgroup_filter_set *filter_set, struct btrfs_qgroup_comparer_set *comp_set) { struct rb_node *n; struct btrfs_qgroup *entry; int ret; qgroup_lookup_init(sort_tree); pre_process_filter_set(all_qgroups, filter_set); n = rb_last(&all_qgroups->root); while (n) { entry = rb_entry(n, struct btrfs_qgroup, rb_node); ret = filter_qgroup(entry, filter_set); if (ret) { sort_tree_insert(sort_tree, entry, comp_set); update_columns_max_len(entry); } n = rb_prev(n); } } static int __qgroups_search(int fd, struct qgroup_lookup *qgroup_lookup) { int ret; struct btrfs_ioctl_search_args args; struct btrfs_ioctl_search_key *sk = &args.key; struct btrfs_ioctl_search_header *sh; unsigned long off = 0; unsigned int i; int e; struct btrfs_qgroup_info_item *info; struct btrfs_qgroup_limit_item *limit; struct btrfs_qgroup *bq; struct btrfs_qgroup *bq1; u64 a1; u64 a2; u64 a3; u64 a4; u64 a5; memset(&args, 0, sizeof(args)); sk->tree_id = BTRFS_QUOTA_TREE_OBJECTID; sk->max_type = BTRFS_QGROUP_RELATION_KEY; sk->min_type = BTRFS_QGROUP_INFO_KEY; sk->max_objectid = (u64)-1; sk->max_offset = (u64)-1; sk->max_transid = (u64)-1; sk->nr_items = 4096; qgroup_lookup_init(qgroup_lookup); while (1) { ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args); e = errno; if (ret < 0) { fprintf(stderr, "ERROR: can't perform the search - %s\n", strerror(e)); return ret; } /* the ioctl returns the number of item it found in nr_items */ if (sk->nr_items == 0) break; off = 0; /* * for each item, pull the key out of the header and then * read the root_ref item it contains */ for (i = 0; i < sk->nr_items; i++) { sh = (struct btrfs_ioctl_search_header *)(args.buf + off); off += sizeof(*sh); if (sh->type == BTRFS_QGROUP_INFO_KEY) { info = (struct btrfs_qgroup_info_item *) (args.buf + off); a1 = btrfs_stack_qgroup_info_generation(info); a2 = btrfs_stack_qgroup_info_referenced(info); a3 = btrfs_stack_qgroup_info_referenced_compressed (info); a4 = btrfs_stack_qgroup_info_exclusive(info); a5 = btrfs_stack_qgroup_info_exclusive_compressed (info); add_qgroup(qgroup_lookup, sh->offset, a1, a2, a3, a4, a5, 0, 0, 0, 0, 0, 0, 0); } else if (sh->type == BTRFS_QGROUP_LIMIT_KEY) { limit = (struct btrfs_qgroup_limit_item *) (args.buf + off); a1 = btrfs_stack_qgroup_limit_flags(limit); a2 = btrfs_stack_qgroup_limit_max_referenced (limit); a3 = btrfs_stack_qgroup_limit_max_exclusive (limit); a4 = btrfs_stack_qgroup_limit_rsv_referenced (limit); a5 = btrfs_stack_qgroup_limit_rsv_exclusive (limit); add_qgroup(qgroup_lookup, sh->offset, 0, 0, 0, 0, 0, a1, a2, a3, a4, a5, 0, 0); } else if (sh->type == BTRFS_QGROUP_RELATION_KEY) { if (sh->offset < sh->objectid) goto skip; bq = qgroup_tree_search(qgroup_lookup, sh->offset); if (!bq) goto skip; bq1 = qgroup_tree_search(qgroup_lookup, sh->objectid); if (!bq1) goto skip; add_qgroup(qgroup_lookup, sh->offset, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, bq, bq1); } else goto done; skip: off += sh->len; /* * record the mins in sk so we can make sure the * next search doesn't repeat this root */ sk->min_type = sh->type; sk->min_offset = sh->offset; sk->min_objectid = sh->objectid; } sk->nr_items = 4096; /* * this iteration is done, step forward one qgroup for the next * ioctl */ if (sk->min_offset < (u64)-1) sk->min_offset++; else break; } done: return ret; } static void print_all_qgroups(struct qgroup_lookup *qgroup_lookup) { struct rb_node *n; struct btrfs_qgroup *entry; print_table_head(); n = rb_first(&qgroup_lookup->root); while (n) { entry = rb_entry(n, struct btrfs_qgroup, sort_node); print_single_qgroup_table(entry); n = rb_next(n); } } int btrfs_show_qgroups(int fd, struct btrfs_qgroup_filter_set *filter_set, struct btrfs_qgroup_comparer_set *comp_set) { struct qgroup_lookup qgroup_lookup; struct qgroup_lookup sort_tree; int ret; ret = __qgroups_search(fd, &qgroup_lookup); if (ret) return ret; __filter_and_sort_qgroups(&qgroup_lookup, &sort_tree, filter_set, comp_set); print_all_qgroups(&sort_tree); __free_all_qgroups(&qgroup_lookup); btrfs_qgroup_free_filter_set(filter_set); return ret; } u64 btrfs_get_path_rootid(int fd) { int ret; struct btrfs_ioctl_ino_lookup_args args; memset(&args, 0, sizeof(args)); args.objectid = BTRFS_FIRST_FREE_OBJECTID; ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args); if (ret < 0) { fprintf(stderr, "ERROR: can't perform the search - %s\n", strerror(errno)); return ret; } return args.treeid; } int btrfs_qgroup_parse_sort_string(char *opt_arg, struct btrfs_qgroup_comparer_set **comps) { int order; int flag; char *p; char **ptr_argv; int what_to_sort; while ((p = strtok(opt_arg, ",")) != NULL) { flag = 0; ptr_argv = all_sort_items; while (*ptr_argv) { if (strcmp(*ptr_argv, p) == 0) { flag = 1; break; } else { p++; if (strcmp(*ptr_argv, p) == 0) { flag = 1; p--; break; } p--; } ptr_argv++; } if (flag == 0) return -1; else { if (*p == '+') { order = 0; p++; } else if (*p == '-') { order = 1; p++; } else order = 0; what_to_sort = btrfs_qgroup_get_sort_item(p); if (what_to_sort < 0) return -1; btrfs_qgroup_setup_comparer(comps, what_to_sort, order); } opt_arg = NULL; } return 0; } u64 parse_qgroupid(char *p) { char *s = strchr(p, '/'); char *ptr_src_end = p + strlen(p); char *ptr_parse_end = NULL; u64 level; u64 id; if (!s) { id = strtoull(p, &ptr_parse_end, 10); if (ptr_parse_end != ptr_src_end) goto err; return id; } level = strtoull(p, &ptr_parse_end, 10); if (ptr_parse_end != s) goto err; id = strtoull(s+1, &ptr_parse_end, 10); if (ptr_parse_end != ptr_src_end) goto err; return (level << 48) | id; err: fprintf(stderr, "ERROR:invalid qgroupid\n"); exit(-1); } int qgroup_inherit_size(struct btrfs_qgroup_inherit *p) { return sizeof(*p) + sizeof(p->qgroups[0]) * (p->num_qgroups + 2 * p->num_ref_copies + 2 * p->num_excl_copies); } static int qgroup_inherit_realloc(struct btrfs_qgroup_inherit **inherit, int n, int pos) { struct btrfs_qgroup_inherit *out; int nitems = 0; if (*inherit) { nitems = (*inherit)->num_qgroups + (*inherit)->num_ref_copies + (*inherit)->num_excl_copies; } out = calloc(sizeof(*out) + sizeof(out->qgroups[0]) * (nitems + n), 1); if (out == NULL) { fprintf(stderr, "ERROR: Not enough memory\n"); return 13; } if (*inherit) { struct btrfs_qgroup_inherit *i = *inherit; int s = sizeof(out->qgroups[0]); out->num_qgroups = i->num_qgroups; out->num_ref_copies = i->num_ref_copies; out->num_excl_copies = i->num_excl_copies; memcpy(out->qgroups, i->qgroups, pos * s); memcpy(out->qgroups + pos + n, i->qgroups + pos, (nitems - pos) * s); } free(*inherit); *inherit = out; return 0; } int qgroup_inherit_add_group(struct btrfs_qgroup_inherit **inherit, char *arg) { int ret; u64 qgroupid = parse_qgroupid(arg); int pos = 0; if (qgroupid == 0) { fprintf(stderr, "ERROR: bad qgroup specification\n"); return 12; } if (*inherit) pos = (*inherit)->num_qgroups; ret = qgroup_inherit_realloc(inherit, 1, pos); if (ret) return ret; (*inherit)->qgroups[(*inherit)->num_qgroups++] = qgroupid; return 0; } int qgroup_inherit_add_copy(struct btrfs_qgroup_inherit **inherit, char *arg, int type) { int ret; u64 qgroup_src; u64 qgroup_dst; char *p; int pos = 0; p = strchr(arg, ':'); if (!p) { bad: fprintf(stderr, "ERROR: bad copy specification\n"); return 12; } *p = 0; qgroup_src = parse_qgroupid(arg); qgroup_dst = parse_qgroupid(p + 1); *p = ':'; if (!qgroup_src || !qgroup_dst) goto bad; if (*inherit) pos = (*inherit)->num_qgroups + (*inherit)->num_ref_copies * 2 * type; ret = qgroup_inherit_realloc(inherit, 2, pos); if (ret) return ret; (*inherit)->qgroups[pos++] = qgroup_src; (*inherit)->qgroups[pos++] = qgroup_dst; if (!type) ++(*inherit)->num_ref_copies; else ++(*inherit)->num_excl_copies; return 0; } partclone-0.2.86/src/btrfs/qgroup.h000066400000000000000000000057701262102574200172050ustar00rootroot00000000000000/* * Copyright (C) 2012 STRATO. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. */ #ifndef _BTRFS_QGROUP_H #define _BTRFS_QGROUP_H #include "ioctl.h" #include "kerncompat.h" struct btrfs_qgroup; typedef int (*btrfs_qgroup_filter_func)(struct btrfs_qgroup *, u64); typedef int (*btrfs_qgroup_comp_func)(struct btrfs_qgroup *, struct btrfs_qgroup *, int); struct btrfs_qgroup_filter { btrfs_qgroup_filter_func filter_func; u64 data; }; struct btrfs_qgroup_comparer { btrfs_qgroup_comp_func comp_func; int is_descending; }; struct btrfs_qgroup_filter_set { int total; int nfilters; struct btrfs_qgroup_filter filters[0]; }; struct btrfs_qgroup_comparer_set { int total; int ncomps; struct btrfs_qgroup_comparer comps[0]; }; enum btrfs_qgroup_column_enum { BTRFS_QGROUP_QGROUPID, BTRFS_QGROUP_RFER, BTRFS_QGROUP_EXCL, BTRFS_QGROUP_MAX_RFER, BTRFS_QGROUP_MAX_EXCL, BTRFS_QGROUP_PARENT, BTRFS_QGROUP_CHILD, BTRFS_QGROUP_ALL, }; enum btrfs_qgroup_comp_enum { BTRFS_QGROUP_COMP_QGROUPID, BTRFS_QGROUP_COMP_RFER, BTRFS_QGROUP_COMP_EXCL, BTRFS_QGROUP_COMP_MAX_RFER, BTRFS_QGROUP_COMP_MAX_EXCL, BTRFS_QGROUP_COMP_MAX }; enum btrfs_qgroup_filter_enum { BTRFS_QGROUP_FILTER_PARENT, BTRFS_QGROUP_FILTER_ALL_PARENT, BTRFS_QGROUP_FILTER_MAX, }; int btrfs_qgroup_parse_sort_string(char *opt_arg, struct btrfs_qgroup_comparer_set **comps); u64 btrfs_get_path_rootid(int fd); int btrfs_show_qgroups(int fd, struct btrfs_qgroup_filter_set *, struct btrfs_qgroup_comparer_set *); void btrfs_qgroup_setup_print_column(enum btrfs_qgroup_column_enum column); struct btrfs_qgroup_filter_set *btrfs_qgroup_alloc_filter_set(void); void btrfs_qgroup_free_filter_set(struct btrfs_qgroup_filter_set *filter_set); int btrfs_qgroup_setup_filter(struct btrfs_qgroup_filter_set **filter_set, enum btrfs_qgroup_filter_enum, u64 data); struct btrfs_qgroup_comparer_set *btrfs_qgroup_alloc_comparer_set(void); void btrfs_qgroup_free_comparer_set(struct btrfs_qgroup_comparer_set *comp_set); int btrfs_qgroup_setup_comparer(struct btrfs_qgroup_comparer_set **comp_set, enum btrfs_qgroup_comp_enum comparer, int is_descending); u64 parse_qgroupid(char *p); int qgroup_inherit_size(struct btrfs_qgroup_inherit *p); int qgroup_inherit_add_group(struct btrfs_qgroup_inherit **inherit, char *arg); int qgroup_inherit_add_copy(struct btrfs_qgroup_inherit **inherit, char *arg, int type); #endif partclone-0.2.86/src/btrfs/radix-tree.c000066400000000000000000000504761262102574200177320ustar00rootroot00000000000000/* * Copyright (C) 2007 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. */ /* * Copyright (C) 2001 Momchil Velikov * Portions Copyright (C) 2001 Christoph Hellwig * Copyright (C) 2005 SGI, Christoph Lameter * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "kerncompat.h" #include "radix-tree.h" #ifdef __KERNEL__ #define RADIX_TREE_MAP_SHIFT (CONFIG_BASE_SMALL ? 4 : 6) #else #define RADIX_TREE_MAP_SHIFT 3 /* For more stressful testing */ #endif #define RADIX_TREE_MAP_SIZE (1UL << RADIX_TREE_MAP_SHIFT) #define RADIX_TREE_MAP_MASK (RADIX_TREE_MAP_SIZE-1) #define RADIX_TREE_TAG_LONGS \ ((RADIX_TREE_MAP_SIZE + BITS_PER_LONG - 1) / BITS_PER_LONG) struct radix_tree_node { unsigned int count; void *slots[RADIX_TREE_MAP_SIZE]; unsigned long tags[RADIX_TREE_MAX_TAGS][RADIX_TREE_TAG_LONGS]; }; struct radix_tree_path { struct radix_tree_node *node; int offset; }; #define RADIX_TREE_INDEX_BITS (8 /* CHAR_BIT */ * sizeof(unsigned long)) #define RADIX_TREE_MAX_PATH (RADIX_TREE_INDEX_BITS/RADIX_TREE_MAP_SHIFT + 2) static unsigned long height_to_maxindex[RADIX_TREE_MAX_PATH] __read_mostly; /* * Per-cpu pool of preloaded nodes */ struct radix_tree_preload { int nr; struct radix_tree_node *nodes[RADIX_TREE_MAX_PATH]; }; static struct radix_tree_preload radix_tree_preloads = { 0, }; static inline gfp_t root_gfp_mask(struct radix_tree_root *root) { return root->gfp_mask & __GFP_BITS_MASK; } static int internal_nodes = 0; /* * This assumes that the caller has performed appropriate preallocation, and * that the caller has pinned this thread of control to the current CPU. */ static struct radix_tree_node * radix_tree_node_alloc(struct radix_tree_root *root) { struct radix_tree_node *ret; ret = malloc(sizeof(struct radix_tree_node)); if (ret) { memset(ret, 0, sizeof(struct radix_tree_node)); internal_nodes++; } return ret; } static inline void radix_tree_node_free(struct radix_tree_node *node) { internal_nodes--; free(node); } /* * Load up this CPU's radix_tree_node buffer with sufficient objects to * ensure that the addition of a single element in the tree cannot fail. On * success, return zero, with preemption disabled. On error, return -ENOMEM * with preemption not disabled. */ int radix_tree_preload(gfp_t gfp_mask) { struct radix_tree_preload *rtp; struct radix_tree_node *node; int ret = -ENOMEM; preempt_disable(); rtp = &__get_cpu_var(radix_tree_preloads); while (rtp->nr < ARRAY_SIZE(rtp->nodes)) { preempt_enable(); node = radix_tree_node_alloc(NULL); if (node == NULL) goto out; preempt_disable(); rtp = &__get_cpu_var(radix_tree_preloads); if (rtp->nr < ARRAY_SIZE(rtp->nodes)) rtp->nodes[rtp->nr++] = node; else radix_tree_node_free(node); } ret = 0; out: return ret; } static inline void tag_set(struct radix_tree_node *node, unsigned int tag, int offset) { __set_bit(offset, node->tags[tag]); } static inline void tag_clear(struct radix_tree_node *node, unsigned int tag, int offset) { __clear_bit(offset, node->tags[tag]); } static inline int tag_get(struct radix_tree_node *node, unsigned int tag, int offset) { return test_bit(offset, node->tags[tag]); } static inline void root_tag_set(struct radix_tree_root *root, unsigned int tag) { root->gfp_mask |= (__force gfp_t)(1 << (tag + __GFP_BITS_SHIFT)); } static inline void root_tag_clear(struct radix_tree_root *root, unsigned int tag) { root->gfp_mask &= (__force gfp_t)~(1 << (tag + __GFP_BITS_SHIFT)); } static inline void root_tag_clear_all(struct radix_tree_root *root) { root->gfp_mask &= __GFP_BITS_MASK; } static inline int root_tag_get(struct radix_tree_root *root, unsigned int tag) { return (__force unsigned)root->gfp_mask & (1 << (tag + __GFP_BITS_SHIFT)); } /* * Returns 1 if any slot in the node has this tag set. * Otherwise returns 0. */ static inline int any_tag_set(struct radix_tree_node *node, unsigned int tag) { int idx; for (idx = 0; idx < RADIX_TREE_TAG_LONGS; idx++) { if (node->tags[tag][idx]) return 1; } return 0; } /* * Return the maximum key which can be store into a * radix tree with height HEIGHT. */ static inline unsigned long radix_tree_maxindex(unsigned int height) { return height_to_maxindex[height]; } /* * Extend a radix tree so it can store key @index. */ static int radix_tree_extend(struct radix_tree_root *root, unsigned long index) { struct radix_tree_node *node; unsigned int height; int tag; /* Figure out what the height should be. */ height = root->height + 1; while (index > radix_tree_maxindex(height)) height++; if (root->rnode == NULL) { root->height = height; goto out; } do { if (!(node = radix_tree_node_alloc(root))) return -ENOMEM; /* Increase the height. */ node->slots[0] = root->rnode; /* Propagate the aggregated tag info into the new root */ for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++) { if (root_tag_get(root, tag)) tag_set(node, tag, 0); } node->count = 1; root->rnode = node; root->height++; } while (height > root->height); out: return 0; } /** * radix_tree_insert - insert into a radix tree * @root: radix tree root * @index: index key * @item: item to insert * * Insert an item into the radix tree at position @index. */ int radix_tree_insert(struct radix_tree_root *root, unsigned long index, void *item) { struct radix_tree_node *node = NULL, *slot; unsigned int height, shift; int offset; int error; /* Make sure the tree is high enough. */ if (index > radix_tree_maxindex(root->height)) { error = radix_tree_extend(root, index); if (error) return error; } slot = root->rnode; height = root->height; shift = (height-1) * RADIX_TREE_MAP_SHIFT; offset = 0; /* uninitialised var warning */ while (height > 0) { if (slot == NULL) { /* Have to add a child node. */ if (!(slot = radix_tree_node_alloc(root))) return -ENOMEM; if (node) { node->slots[offset] = slot; node->count++; } else root->rnode = slot; } /* Go a level down */ offset = (index >> shift) & RADIX_TREE_MAP_MASK; node = slot; slot = node->slots[offset]; shift -= RADIX_TREE_MAP_SHIFT; height--; } if (slot != NULL) return -EEXIST; if (node) { node->count++; node->slots[offset] = item; BUG_ON(tag_get(node, 0, offset)); BUG_ON(tag_get(node, 1, offset)); } else { root->rnode = item; BUG_ON(root_tag_get(root, 0)); BUG_ON(root_tag_get(root, 1)); } return 0; } static inline void **__lookup_slot(struct radix_tree_root *root, unsigned long index) { unsigned int height, shift; struct radix_tree_node **slot; height = root->height; if (index > radix_tree_maxindex(height)) return NULL; if (height == 0 && root->rnode) return (void *)&root->rnode; shift = (height-1) * RADIX_TREE_MAP_SHIFT; slot = &root->rnode; while (height > 0) { if (*slot == NULL) return NULL; slot = (struct radix_tree_node **) ((*slot)->slots + ((index >> shift) & RADIX_TREE_MAP_MASK)); shift -= RADIX_TREE_MAP_SHIFT; height--; } return (void **)slot; } /** * radix_tree_lookup_slot - lookup a slot in a radix tree * @root: radix tree root * @index: index key * * Lookup the slot corresponding to the position @index in the radix tree * @root. This is useful for update-if-exists operations. */ void **radix_tree_lookup_slot(struct radix_tree_root *root, unsigned long index) { return __lookup_slot(root, index); } /** * radix_tree_lookup - perform lookup operation on a radix tree * @root: radix tree root * @index: index key * * Lookup the item at the position @index in the radix tree @root. */ void *radix_tree_lookup(struct radix_tree_root *root, unsigned long index) { void **slot; slot = __lookup_slot(root, index); return slot != NULL ? *slot : NULL; } /** * radix_tree_tag_set - set a tag on a radix tree node * @root: radix tree root * @index: index key * @tag: tag index * * Set the search tag (which must be < RADIX_TREE_MAX_TAGS) * corresponding to @index in the radix tree. From * the root all the way down to the leaf node. * * Returns the address of the tagged item. Setting a tag on a not-present * item is a bug. */ void *radix_tree_tag_set(struct radix_tree_root *root, unsigned long index, unsigned int tag) { unsigned int height, shift; struct radix_tree_node *slot; height = root->height; BUG_ON(index > radix_tree_maxindex(height)); slot = root->rnode; shift = (height - 1) * RADIX_TREE_MAP_SHIFT; while (height > 0) { int offset; offset = (index >> shift) & RADIX_TREE_MAP_MASK; if (!tag_get(slot, tag, offset)) tag_set(slot, tag, offset); slot = slot->slots[offset]; BUG_ON(slot == NULL); shift -= RADIX_TREE_MAP_SHIFT; height--; } /* set the root's tag bit */ if (slot && !root_tag_get(root, tag)) root_tag_set(root, tag); return slot; } /** * radix_tree_tag_clear - clear a tag on a radix tree node * @root: radix tree root * @index: index key * @tag: tag index * * Clear the search tag (which must be < RADIX_TREE_MAX_TAGS) * corresponding to @index in the radix tree. If * this causes the leaf node to have no tags set then clear the tag in the * next-to-leaf node, etc. * * Returns the address of the tagged item on success, else NULL. ie: * has the same return value and semantics as radix_tree_lookup(). */ void *radix_tree_tag_clear(struct radix_tree_root *root, unsigned long index, unsigned int tag) { struct radix_tree_path path[RADIX_TREE_MAX_PATH], *pathp = path; struct radix_tree_node *slot = NULL; unsigned int height, shift; height = root->height; if (index > radix_tree_maxindex(height)) goto out; shift = (height - 1) * RADIX_TREE_MAP_SHIFT; pathp->node = NULL; slot = root->rnode; while (height > 0) { int offset; if (slot == NULL) goto out; offset = (index >> shift) & RADIX_TREE_MAP_MASK; pathp[1].offset = offset; pathp[1].node = slot; slot = slot->slots[offset]; pathp++; shift -= RADIX_TREE_MAP_SHIFT; height--; } if (slot == NULL) goto out; while (pathp->node) { if (!tag_get(pathp->node, tag, pathp->offset)) goto out; tag_clear(pathp->node, tag, pathp->offset); if (any_tag_set(pathp->node, tag)) goto out; pathp--; } /* clear the root's tag bit */ if (root_tag_get(root, tag)) root_tag_clear(root, tag); out: return slot; } #ifndef __KERNEL__ /* Only the test harness uses this at present */ /** * radix_tree_tag_get - get a tag on a radix tree node * @root: radix tree root * @index: index key * @tag: tag index (< RADIX_TREE_MAX_TAGS) * * Return values: * * 0: tag not present or not set * 1: tag set */ int radix_tree_tag_get(struct radix_tree_root *root, unsigned long index, unsigned int tag) { unsigned int height, shift; struct radix_tree_node *slot; int saw_unset_tag = 0; height = root->height; if (index > radix_tree_maxindex(height)) return 0; /* check the root's tag bit */ if (!root_tag_get(root, tag)) return 0; if (height == 0) return 1; shift = (height - 1) * RADIX_TREE_MAP_SHIFT; slot = root->rnode; for ( ; ; ) { int offset; if (slot == NULL) return 0; offset = (index >> shift) & RADIX_TREE_MAP_MASK; /* * This is just a debug check. Later, we can bale as soon as * we see an unset tag. */ if (!tag_get(slot, tag, offset)) saw_unset_tag = 1; if (height == 1) { int ret = tag_get(slot, tag, offset); BUG_ON(ret && saw_unset_tag); return !!ret; } slot = slot->slots[offset]; shift -= RADIX_TREE_MAP_SHIFT; height--; } } #endif static unsigned int __lookup(struct radix_tree_root *root, void **results, unsigned long index, unsigned int max_items, unsigned long *next_index) { unsigned int nr_found = 0; unsigned int shift, height; struct radix_tree_node *slot; unsigned long i; height = root->height; if (height == 0) { if (root->rnode && index == 0) results[nr_found++] = root->rnode; goto out; } shift = (height-1) * RADIX_TREE_MAP_SHIFT; slot = root->rnode; for ( ; height > 1; height--) { for (i = (index >> shift) & RADIX_TREE_MAP_MASK ; i < RADIX_TREE_MAP_SIZE; i++) { if (slot->slots[i] != NULL) break; index &= ~((1UL << shift) - 1); index += 1UL << shift; if (index == 0) goto out; /* 32-bit wraparound */ } if (i == RADIX_TREE_MAP_SIZE) goto out; shift -= RADIX_TREE_MAP_SHIFT; slot = slot->slots[i]; } /* Bottom level: grab some items */ for (i = index & RADIX_TREE_MAP_MASK; i < RADIX_TREE_MAP_SIZE; i++) { index++; if (slot->slots[i]) { results[nr_found++] = slot->slots[i]; if (nr_found == max_items) goto out; } } out: *next_index = index; return nr_found; } /** * radix_tree_gang_lookup - perform multiple lookup on a radix tree * @root: radix tree root * @results: where the results of the lookup are placed * @first_index: start the lookup from this key * @max_items: place up to this many items at *results * * Performs an index-ascending scan of the tree for present items. Places * them at *@results and returns the number of items which were placed at * *@results. * * The implementation is naive. */ unsigned int radix_tree_gang_lookup(struct radix_tree_root *root, void **results, unsigned long first_index, unsigned int max_items) { const unsigned long max_index = radix_tree_maxindex(root->height); unsigned long cur_index = first_index; unsigned int ret = 0; while (ret < max_items) { unsigned int nr_found; unsigned long next_index; /* Index of next search */ if (cur_index > max_index) break; nr_found = __lookup(root, results + ret, cur_index, max_items - ret, &next_index); ret += nr_found; if (next_index == 0) break; cur_index = next_index; } return ret; } /* * FIXME: the two tag_get()s here should use find_next_bit() instead of * open-coding the search. */ static unsigned int __lookup_tag(struct radix_tree_root *root, void **results, unsigned long index, unsigned int max_items, unsigned long *next_index, unsigned int tag) { unsigned int nr_found = 0; unsigned int shift; unsigned int height = root->height; struct radix_tree_node *slot; if (height == 0) { if (root->rnode && index == 0) results[nr_found++] = root->rnode; goto out; } shift = (height - 1) * RADIX_TREE_MAP_SHIFT; slot = root->rnode; do { unsigned long i = (index >> shift) & RADIX_TREE_MAP_MASK; for ( ; i < RADIX_TREE_MAP_SIZE; i++) { if (tag_get(slot, tag, i)) { BUG_ON(slot->slots[i] == NULL); break; } index &= ~((1UL << shift) - 1); index += 1UL << shift; if (index == 0) goto out; /* 32-bit wraparound */ } if (i == RADIX_TREE_MAP_SIZE) goto out; height--; if (height == 0) { /* Bottom level: grab some items */ unsigned long j = index & RADIX_TREE_MAP_MASK; for ( ; j < RADIX_TREE_MAP_SIZE; j++) { index++; if (tag_get(slot, tag, j)) { BUG_ON(slot->slots[j] == NULL); results[nr_found++] = slot->slots[j]; if (nr_found == max_items) goto out; } } } shift -= RADIX_TREE_MAP_SHIFT; slot = slot->slots[i]; } while (height > 0); out: *next_index = index; return nr_found; } /** * radix_tree_gang_lookup_tag - perform multiple lookup on a radix tree * based on a tag * @root: radix tree root * @results: where the results of the lookup are placed * @first_index: start the lookup from this key * @max_items: place up to this many items at *results * @tag: the tag index (< RADIX_TREE_MAX_TAGS) * * Performs an index-ascending scan of the tree for present items which * have the tag indexed by @tag set. Places the items at *@results and * returns the number of items which were placed at *@results. */ unsigned int radix_tree_gang_lookup_tag(struct radix_tree_root *root, void **results, unsigned long first_index, unsigned int max_items, unsigned int tag) { const unsigned long max_index = radix_tree_maxindex(root->height); unsigned long cur_index = first_index; unsigned int ret = 0; /* check the root's tag bit */ if (!root_tag_get(root, tag)) return 0; while (ret < max_items) { unsigned int nr_found; unsigned long next_index; /* Index of next search */ if (cur_index > max_index) break; nr_found = __lookup_tag(root, results + ret, cur_index, max_items - ret, &next_index, tag); ret += nr_found; if (next_index == 0) break; cur_index = next_index; } return ret; } /** * radix_tree_shrink - shrink height of a radix tree to minimal * @root radix tree root */ static inline void radix_tree_shrink(struct radix_tree_root *root) { /* try to shrink tree height */ while (root->height > 0 && root->rnode->count == 1 && root->rnode->slots[0]) { struct radix_tree_node *to_free = root->rnode; root->rnode = to_free->slots[0]; root->height--; /* must only free zeroed nodes into the slab */ tag_clear(to_free, 0, 0); tag_clear(to_free, 1, 0); to_free->slots[0] = NULL; to_free->count = 0; radix_tree_node_free(to_free); } } /** * radix_tree_delete - delete an item from a radix tree * @root: radix tree root * @index: index key * * Remove the item at @index from the radix tree rooted at @root. * * Returns the address of the deleted item, or NULL if it was not present. */ void *radix_tree_delete(struct radix_tree_root *root, unsigned long index) { struct radix_tree_path path[RADIX_TREE_MAX_PATH], *pathp = path; struct radix_tree_node *slot = NULL; unsigned int height, shift; int tag; int offset; height = root->height; if (index > radix_tree_maxindex(height)) goto out; slot = root->rnode; if (height == 0 && root->rnode) { root_tag_clear_all(root); root->rnode = NULL; goto out; } shift = (height - 1) * RADIX_TREE_MAP_SHIFT; pathp->node = NULL; do { if (slot == NULL) goto out; pathp++; offset = (index >> shift) & RADIX_TREE_MAP_MASK; pathp->offset = offset; pathp->node = slot; slot = slot->slots[offset]; shift -= RADIX_TREE_MAP_SHIFT; height--; } while (height > 0); if (slot == NULL) goto out; /* * Clear all tags associated with the just-deleted item */ for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++) { if (tag_get(pathp->node, tag, pathp->offset)) radix_tree_tag_clear(root, index, tag); } /* Now free the nodes we do not need anymore */ while (pathp->node) { pathp->node->slots[pathp->offset] = NULL; pathp->node->count--; if (pathp->node->count) { if (pathp->node == root->rnode) radix_tree_shrink(root); goto out; } /* Node with zero slots in use so free it */ radix_tree_node_free(pathp->node); pathp--; } root_tag_clear_all(root); root->height = 0; root->rnode = NULL; out: return slot; } /** * radix_tree_tagged - test whether any items in the tree are tagged * @root: radix tree root * @tag: tag to test */ int radix_tree_tagged(struct radix_tree_root *root, unsigned int tag) { return root_tag_get(root, tag); } static unsigned long __maxindex(unsigned int height) { unsigned int tmp = height * RADIX_TREE_MAP_SHIFT; unsigned long index = ~0UL; if (tmp < RADIX_TREE_INDEX_BITS) index = (index >> (RADIX_TREE_INDEX_BITS - tmp - 1)) >> 1; return index; } static void radix_tree_init_maxindex(void) { unsigned int i; for (i = 0; i < ARRAY_SIZE(height_to_maxindex); i++) height_to_maxindex[i] = __maxindex(i); } void radix_tree_init(void) { radix_tree_init_maxindex(); } partclone-0.2.86/src/btrfs/radix-tree.h000066400000000000000000000064171262102574200177330ustar00rootroot00000000000000/* * Copyright (C) 2007 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. */ /* * Copyright (C) 2001 Momchil Velikov * Portions Copyright (C) 2001 Christoph Hellwig * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef _LINUX_RADIX_TREE_H #define _LINUX_RADIX_TREE_H #if BTRFS_FLAT_INCLUDES #include "kerncompat.h" #else #include #endif /* BTRFS_FLAT_INCLUDES */ #define RADIX_TREE_MAX_TAGS 2 /* root tags are stored in gfp_mask, shifted by __GFP_BITS_SHIFT */ struct radix_tree_root { unsigned int height; gfp_t gfp_mask; struct radix_tree_node *rnode; }; #define RADIX_TREE_INIT(mask) { \ .height = 0, \ .gfp_mask = (mask), \ .rnode = NULL, \ } #define RADIX_TREE(name, mask) \ struct radix_tree_root name = RADIX_TREE_INIT(mask) #define INIT_RADIX_TREE(root, mask) \ do { \ (root)->height = 0; \ (root)->gfp_mask = (mask); \ (root)->rnode = NULL; \ } while (0) int radix_tree_insert(struct radix_tree_root *, unsigned long, void *); void *radix_tree_lookup(struct radix_tree_root *, unsigned long); void **radix_tree_lookup_slot(struct radix_tree_root *, unsigned long); void *radix_tree_delete(struct radix_tree_root *, unsigned long); unsigned int radix_tree_gang_lookup(struct radix_tree_root *root, void **results, unsigned long first_index, unsigned int max_items); int radix_tree_preload(gfp_t gfp_mask); void radix_tree_init(void); void *radix_tree_tag_set(struct radix_tree_root *root, unsigned long index, unsigned int tag); void *radix_tree_tag_clear(struct radix_tree_root *root, unsigned long index, unsigned int tag); int radix_tree_tag_get(struct radix_tree_root *root, unsigned long index, unsigned int tag); unsigned int radix_tree_gang_lookup_tag(struct radix_tree_root *root, void **results, unsigned long first_index, unsigned int max_items, unsigned int tag); int radix_tree_tagged(struct radix_tree_root *root, unsigned int tag); static inline void radix_tree_preload_end(void) { preempt_enable(); } #endif /* _LINUX_RADIX_TREE_H */ partclone-0.2.86/src/btrfs/raid6.c000066400000000000000000000050121262102574200166550ustar00rootroot00000000000000/* -*- linux-c -*- ------------------------------------------------------- * * * Copyright 2002-2004 H. Peter Anvin - All Rights Reserved * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, Inc., 53 Temple Place Ste 330, * Boston MA 02111-1307, USA; either version 2 of the License, or * (at your option) any later version; incorporated herein by reference. * * ----------------------------------------------------------------------- */ /* * raid6int1.c * * 1-way unrolled portable integer math RAID-6 instruction set * * This file was postprocessed using unroll.pl and then ported to userspace */ #include #include #include "kerncompat.h" #include "ctree.h" #include "disk-io.h" /* * This is the C data type to use */ /* Change this from BITS_PER_LONG if there is something better... */ #if BITS_PER_LONG == 64 # define NBYTES(x) ((x) * 0x0101010101010101UL) # define NSIZE 8 # define NSHIFT 3 typedef uint64_t unative_t; #else # define NBYTES(x) ((x) * 0x01010101U) # define NSIZE 4 # define NSHIFT 2 typedef uint32_t unative_t; #endif /* * These sub-operations are separate inlines since they can sometimes be * specially optimized using architecture-specific hacks. */ /* * The SHLBYTE() operation shifts each byte left by 1, *not* * rolling over into the next byte */ static inline __attribute_const__ unative_t SHLBYTE(unative_t v) { unative_t vv; vv = (v << 1) & NBYTES(0xfe); return vv; } /* * The MASK() operation returns 0xFF in any byte for which the high * bit is 1, 0x00 for any byte for which the high bit is 0. */ static inline __attribute_const__ unative_t MASK(unative_t v) { unative_t vv; vv = v & NBYTES(0x80); vv = (vv << 1) - (vv >> 7); /* Overflow on the top bit is OK */ return vv; } void raid6_gen_syndrome(int disks, size_t bytes, void **ptrs) { uint8_t **dptr = (uint8_t **)ptrs; uint8_t *p, *q; int d, z, z0; unative_t wd0, wq0, wp0, w10, w20; z0 = disks - 3; /* Highest data disk */ p = dptr[z0+1]; /* XOR parity */ q = dptr[z0+2]; /* RS syndrome */ for ( d = 0 ; d < bytes ; d += NSIZE*1 ) { wq0 = wp0 = *(unative_t *)&dptr[z0][d+0*NSIZE]; for ( z = z0-1 ; z >= 0 ; z-- ) { wd0 = *(unative_t *)&dptr[z][d+0*NSIZE]; wp0 ^= wd0; w20 = MASK(wq0); w10 = SHLBYTE(wq0); w20 &= NBYTES(0x1d); w10 ^= w20; wq0 = w10 ^ wd0; } *(unative_t *)&p[d+NSIZE*0] = wp0; *(unative_t *)&q[d+NSIZE*0] = wq0; } } partclone-0.2.86/src/btrfs/rbtree-utils.c000066400000000000000000000034041262102574200202740ustar00rootroot00000000000000/* * Copyright (C) 2014 Facebook. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. */ #include "rbtree-utils.h" int rb_insert(struct rb_root *root, struct rb_node *node, rb_compare_nodes comp) { struct rb_node **p = &root->rb_node; struct rb_node *parent = NULL; int ret; while(*p) { parent = *p; ret = comp(parent, node); if (ret < 0) p = &(*p)->rb_left; else if (ret > 0) p = &(*p)->rb_right; else return -EEXIST; } rb_link_node(node, parent, p); rb_insert_color(node, root); return 0; } struct rb_node *rb_search(struct rb_root *root, void *key, rb_compare_keys comp, struct rb_node **next_ret) { struct rb_node *n = root->rb_node; struct rb_node *parent = NULL; int ret = 0; while(n) { parent = n; ret = comp(n, key); if (ret < 0) n = n->rb_left; else if (ret > 0) n = n->rb_right; else return n; } if (!next_ret) return NULL; if (parent && ret > 0) parent = rb_next(parent); *next_ret = parent; return NULL; } void rb_free_nodes(struct rb_root *root, rb_free_node free_node) { struct rb_node *node; while ((node = rb_first(root))) { rb_erase(node, root); free_node(node); } } partclone-0.2.86/src/btrfs/rbtree-utils.h000066400000000000000000000031661262102574200203060ustar00rootroot00000000000000/* * Copyright (C) 2014 Facebook. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. */ #ifndef __RBTREE_UTILS__ #define __RBTREE_UTILS__ #include "rbtree.h" #ifdef __cplusplus extern "C" { #endif /* The common insert/search/free functions */ typedef int (*rb_compare_nodes)(struct rb_node *node1, struct rb_node *node2); typedef int (*rb_compare_keys)(struct rb_node *node, void *key); typedef void (*rb_free_node)(struct rb_node *node); int rb_insert(struct rb_root *root, struct rb_node *node, rb_compare_nodes comp); /* * In some cases, we need return the next node if we don't find the node we * specify. At this time, we can use next_ret. */ struct rb_node *rb_search(struct rb_root *root, void *key, rb_compare_keys comp, struct rb_node **next_ret); void rb_free_nodes(struct rb_root *root, rb_free_node free_node); #define FREE_RB_BASED_TREE(name, free_func) \ static void free_##name##_tree(struct rb_root *root) \ { \ rb_free_nodes(root, free_func); \ } #ifdef __cplusplus } #endif #endif partclone-0.2.86/src/btrfs/rbtree.c000066400000000000000000000353031262102574200171410ustar00rootroot00000000000000/* Red Black Trees (C) 1999 Andrea Arcangeli (C) 2002 David Woodhouse (C) 2012 Michel Lespinasse This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA linux/lib/rbtree.c */ #include "rbtree_augmented.h" /* * red-black trees properties: http://en.wikipedia.org/wiki/Rbtree * * 1) A node is either red or black * 2) The root is black * 3) All leaves (NULL) are black * 4) Both children of every red node are black * 5) Every simple path from root to leaves contains the same number * of black nodes. * * 4 and 5 give the O(log n) guarantee, since 4 implies you cannot have two * consecutive red nodes in a path and every red node is therefore followed by * a black. So if B is the number of black nodes on every simple path (as per * 5), then the longest possible path due to 4 is 2B. * * We shall indicate color with case, where black nodes are uppercase and red * nodes will be lowercase. Unknown color nodes shall be drawn as red within * parentheses and have some accompanying text comment. */ static inline void rb_set_black(struct rb_node *rb) { rb->__rb_parent_color |= RB_BLACK; } static inline struct rb_node *rb_red_parent(struct rb_node *red) { return (struct rb_node *)red->__rb_parent_color; } /* * Helper function for rotations: * - old's parent and color get assigned to new * - old gets assigned new as a parent and 'color' as a color. */ static inline void __rb_rotate_set_parents(struct rb_node *old, struct rb_node *new, struct rb_root *root, int color) { struct rb_node *parent = rb_parent(old); new->__rb_parent_color = old->__rb_parent_color; rb_set_parent_color(old, new, color); __rb_change_child(old, new, parent, root); } static __always_inline void __rb_insert(struct rb_node *node, struct rb_root *root, void (*augment_rotate)(struct rb_node *old, struct rb_node *new)) { struct rb_node *parent = rb_red_parent(node), *gparent, *tmp; while (true) { /* * Loop invariant: node is red * * If there is a black parent, we are done. * Otherwise, take some corrective action as we don't * want a red root or two consecutive red nodes. */ if (!parent) { rb_set_parent_color(node, NULL, RB_BLACK); break; } else if (rb_is_black(parent)) break; gparent = rb_red_parent(parent); tmp = gparent->rb_right; if (parent != tmp) { /* parent == gparent->rb_left */ if (tmp && rb_is_red(tmp)) { /* * Case 1 - color flips * * G g * / \ / \ * p u --> P U * / / * n n * * However, since g's parent might be red, and * 4) does not allow this, we need to recurse * at g. */ rb_set_parent_color(tmp, gparent, RB_BLACK); rb_set_parent_color(parent, gparent, RB_BLACK); node = gparent; parent = rb_parent(node); rb_set_parent_color(node, parent, RB_RED); continue; } tmp = parent->rb_right; if (node == tmp) { /* * Case 2 - left rotate at parent * * G G * / \ / \ * p U --> n U * \ / * n p * * This still leaves us in violation of 4), the * continuation into Case 3 will fix that. */ parent->rb_right = tmp = node->rb_left; node->rb_left = parent; if (tmp) rb_set_parent_color(tmp, parent, RB_BLACK); rb_set_parent_color(parent, node, RB_RED); augment_rotate(parent, node); parent = node; tmp = node->rb_right; } /* * Case 3 - right rotate at gparent * * G P * / \ / \ * p U --> n g * / \ * n U */ gparent->rb_left = tmp; /* == parent->rb_right */ parent->rb_right = gparent; if (tmp) rb_set_parent_color(tmp, gparent, RB_BLACK); __rb_rotate_set_parents(gparent, parent, root, RB_RED); augment_rotate(gparent, parent); break; } else { tmp = gparent->rb_left; if (tmp && rb_is_red(tmp)) { /* Case 1 - color flips */ rb_set_parent_color(tmp, gparent, RB_BLACK); rb_set_parent_color(parent, gparent, RB_BLACK); node = gparent; parent = rb_parent(node); rb_set_parent_color(node, parent, RB_RED); continue; } tmp = parent->rb_left; if (node == tmp) { /* Case 2 - right rotate at parent */ parent->rb_left = tmp = node->rb_right; node->rb_right = parent; if (tmp) rb_set_parent_color(tmp, parent, RB_BLACK); rb_set_parent_color(parent, node, RB_RED); augment_rotate(parent, node); parent = node; tmp = node->rb_left; } /* Case 3 - left rotate at gparent */ gparent->rb_right = tmp; /* == parent->rb_left */ parent->rb_left = gparent; if (tmp) rb_set_parent_color(tmp, gparent, RB_BLACK); __rb_rotate_set_parents(gparent, parent, root, RB_RED); augment_rotate(gparent, parent); break; } } } /* * Inline version for rb_erase() use - we want to be able to inline * and eliminate the dummy_rotate callback there */ static __always_inline void ____rb_erase_color(struct rb_node *parent, struct rb_root *root, void (*augment_rotate)(struct rb_node *old, struct rb_node *new)) { struct rb_node *node = NULL, *sibling, *tmp1, *tmp2; while (true) { /* * Loop invariants: * - node is black (or NULL on first iteration) * - node is not the root (parent is not NULL) * - All leaf paths going through parent and node have a * black node count that is 1 lower than other leaf paths. */ sibling = parent->rb_right; if (node != sibling) { /* node == parent->rb_left */ if (rb_is_red(sibling)) { /* * Case 1 - left rotate at parent * * P S * / \ / \ * N s --> p Sr * / \ / \ * Sl Sr N Sl */ parent->rb_right = tmp1 = sibling->rb_left; sibling->rb_left = parent; rb_set_parent_color(tmp1, parent, RB_BLACK); __rb_rotate_set_parents(parent, sibling, root, RB_RED); augment_rotate(parent, sibling); sibling = tmp1; } tmp1 = sibling->rb_right; if (!tmp1 || rb_is_black(tmp1)) { tmp2 = sibling->rb_left; if (!tmp2 || rb_is_black(tmp2)) { /* * Case 2 - sibling color flip * (p could be either color here) * * (p) (p) * / \ / \ * N S --> N s * / \ / \ * Sl Sr Sl Sr * * This leaves us violating 5) which * can be fixed by flipping p to black * if it was red, or by recursing at p. * p is red when coming from Case 1. */ rb_set_parent_color(sibling, parent, RB_RED); if (rb_is_red(parent)) rb_set_black(parent); else { node = parent; parent = rb_parent(node); if (parent) continue; } break; } /* * Case 3 - right rotate at sibling * (p could be either color here) * * (p) (p) * / \ / \ * N S --> N Sl * / \ \ * sl Sr s * \ * Sr */ sibling->rb_left = tmp1 = tmp2->rb_right; tmp2->rb_right = sibling; parent->rb_right = tmp2; if (tmp1) rb_set_parent_color(tmp1, sibling, RB_BLACK); augment_rotate(sibling, tmp2); tmp1 = sibling; sibling = tmp2; } /* * Case 4 - left rotate at parent + color flips * (p and sl could be either color here. * After rotation, p becomes black, s acquires * p's color, and sl keeps its color) * * (p) (s) * / \ / \ * N S --> P Sr * / \ / \ * (sl) sr N (sl) */ parent->rb_right = tmp2 = sibling->rb_left; sibling->rb_left = parent; rb_set_parent_color(tmp1, sibling, RB_BLACK); if (tmp2) rb_set_parent(tmp2, parent); __rb_rotate_set_parents(parent, sibling, root, RB_BLACK); augment_rotate(parent, sibling); break; } else { sibling = parent->rb_left; if (rb_is_red(sibling)) { /* Case 1 - right rotate at parent */ parent->rb_left = tmp1 = sibling->rb_right; sibling->rb_right = parent; rb_set_parent_color(tmp1, parent, RB_BLACK); __rb_rotate_set_parents(parent, sibling, root, RB_RED); augment_rotate(parent, sibling); sibling = tmp1; } tmp1 = sibling->rb_left; if (!tmp1 || rb_is_black(tmp1)) { tmp2 = sibling->rb_right; if (!tmp2 || rb_is_black(tmp2)) { /* Case 2 - sibling color flip */ rb_set_parent_color(sibling, parent, RB_RED); if (rb_is_red(parent)) rb_set_black(parent); else { node = parent; parent = rb_parent(node); if (parent) continue; } break; } /* Case 3 - right rotate at sibling */ sibling->rb_right = tmp1 = tmp2->rb_left; tmp2->rb_left = sibling; parent->rb_left = tmp2; if (tmp1) rb_set_parent_color(tmp1, sibling, RB_BLACK); augment_rotate(sibling, tmp2); tmp1 = sibling; sibling = tmp2; } /* Case 4 - left rotate at parent + color flips */ parent->rb_left = tmp2 = sibling->rb_right; sibling->rb_right = parent; rb_set_parent_color(tmp1, sibling, RB_BLACK); if (tmp2) rb_set_parent(tmp2, parent); __rb_rotate_set_parents(parent, sibling, root, RB_BLACK); augment_rotate(parent, sibling); break; } } } /* Non-inline version for rb_erase_augmented() use */ void __rb_erase_color(struct rb_node *parent, struct rb_root *root, void (*augment_rotate)(struct rb_node *old, struct rb_node *new)) { ____rb_erase_color(parent, root, augment_rotate); } /* * Non-augmented rbtree manipulation functions. * * We use dummy augmented callbacks here, and have the compiler optimize them * out of the rb_insert_color() and rb_erase() function definitions. */ static inline void dummy_propagate(struct rb_node *node, struct rb_node *stop) {} static inline void dummy_copy(struct rb_node *old, struct rb_node *new) {} static inline void dummy_rotate(struct rb_node *old, struct rb_node *new) {} static const struct rb_augment_callbacks dummy_callbacks = { dummy_propagate, dummy_copy, dummy_rotate }; void rb_insert_color(struct rb_node *node, struct rb_root *root) { __rb_insert(node, root, dummy_rotate); } void rb_erase(struct rb_node *node, struct rb_root *root) { struct rb_node *rebalance; rebalance = __rb_erase_augmented(node, root, &dummy_callbacks); if (rebalance) ____rb_erase_color(rebalance, root, dummy_rotate); } /* * Augmented rbtree manipulation functions. * * This instantiates the same __always_inline functions as in the non-augmented * case, but this time with user-defined callbacks. */ void __rb_insert_augmented(struct rb_node *node, struct rb_root *root, void (*augment_rotate)(struct rb_node *old, struct rb_node *new)) { __rb_insert(node, root, augment_rotate); } /* * This function returns the first node (in sort order) of the tree. */ struct rb_node *rb_first(const struct rb_root *root) { struct rb_node *n; n = root->rb_node; if (!n) return NULL; while (n->rb_left) n = n->rb_left; return n; } struct rb_node *rb_last(const struct rb_root *root) { struct rb_node *n; n = root->rb_node; if (!n) return NULL; while (n->rb_right) n = n->rb_right; return n; } struct rb_node *rb_next(const struct rb_node *node) { struct rb_node *parent; if (RB_EMPTY_NODE(node)) return NULL; /* * If we have a right-hand child, go down and then left as far * as we can. */ if (node->rb_right) { node = node->rb_right; while (node->rb_left) node=node->rb_left; return (struct rb_node *)node; } /* * No right-hand children. Everything down and left is smaller than us, * so any 'next' node must be in the general direction of our parent. * Go up the tree; any time the ancestor is a right-hand child of its * parent, keep going up. First time it's a left-hand child of its * parent, said parent is our 'next' node. */ while ((parent = rb_parent(node)) && node == parent->rb_right) node = parent; return parent; } struct rb_node *rb_prev(const struct rb_node *node) { struct rb_node *parent; if (RB_EMPTY_NODE(node)) return NULL; /* * If we have a left-hand child, go down and then right as far * as we can. */ if (node->rb_left) { node = node->rb_left; while (node->rb_right) node=node->rb_right; return (struct rb_node *)node; } /* * No left-hand children. Go up till we find an ancestor which * is a right-hand child of its parent. */ while ((parent = rb_parent(node)) && node == parent->rb_left) node = parent; return parent; } void rb_replace_node(struct rb_node *victim, struct rb_node *new, struct rb_root *root) { struct rb_node *parent = rb_parent(victim); /* Set the surrounding nodes to point to the replacement */ __rb_change_child(victim, new, parent, root); if (victim->rb_left) rb_set_parent(victim->rb_left, new); if (victim->rb_right) rb_set_parent(victim->rb_right, new); /* Copy the pointers/colour from the victim to the replacement */ *new = *victim; } static struct rb_node *rb_left_deepest_node(const struct rb_node *node) { for (;;) { if (node->rb_left) node = node->rb_left; else if (node->rb_right) node = node->rb_right; else return (struct rb_node *)node; } } struct rb_node *rb_next_postorder(const struct rb_node *node) { const struct rb_node *parent; if (!node) return NULL; parent = rb_parent(node); /* If we're sitting on node, we've already seen our children */ if (parent && node == parent->rb_left && parent->rb_right) { /* If we are the parent's left node, go to the parent's right * node then all the way down to the left */ return rb_left_deepest_node(parent->rb_right); } else /* Otherwise we are the parent's right node, and the parent * should be next */ return (struct rb_node *)parent; } struct rb_node *rb_first_postorder(const struct rb_root *root) { if (!root->rb_node) return NULL; return rb_left_deepest_node(root->rb_node); } partclone-0.2.86/src/btrfs/rbtree.h000066400000000000000000000074761262102574200171600ustar00rootroot00000000000000/* Red Black Trees (C) 1999 Andrea Arcangeli This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA linux/include/linux/rbtree.h To use rbtrees you'll have to implement your own insert and search cores. This will avoid us to use callbacks and to drop drammatically performances. I know it's not the cleaner way, but in C (not in C++) to get performances and genericity... See Documentation/rbtree.txt for documentation and samples. */ #ifndef _LINUX_RBTREE_H #define _LINUX_RBTREE_H #if BTRFS_FLAT_INCLUDES #include "kerncompat.h" #else #include #endif /* BTRFS_FLAT_INCLUDES */ #ifdef __cplusplus extern "C" { #endif struct rb_node { unsigned long __rb_parent_color; struct rb_node *rb_right; struct rb_node *rb_left; } __attribute__((aligned(sizeof(long)))); /* The alignment might seem pointless, but allegedly CRIS needs it */ struct rb_root { struct rb_node *rb_node; }; #define rb_parent(r) ((struct rb_node *)((r)->__rb_parent_color & ~3)) #define RB_ROOT (struct rb_root) { NULL, } #define rb_entry(ptr, type, member) container_of(ptr, type, member) #define RB_EMPTY_ROOT(root) ((root)->rb_node == NULL) /* 'empty' nodes are nodes that are known not to be inserted in an rbree */ #define RB_EMPTY_NODE(node) \ ((node)->__rb_parent_color == (unsigned long)(node)) #define RB_CLEAR_NODE(node) \ ((node)->__rb_parent_color = (unsigned long)(node)) extern void rb_insert_color(struct rb_node *, struct rb_root *); extern void rb_erase(struct rb_node *, struct rb_root *); /* Find logical next and previous nodes in a tree */ extern struct rb_node *rb_next(const struct rb_node *); extern struct rb_node *rb_prev(const struct rb_node *); extern struct rb_node *rb_first(const struct rb_root *); extern struct rb_node *rb_last(const struct rb_root *); /* Postorder iteration - always visit the parent after its children */ extern struct rb_node *rb_first_postorder(const struct rb_root *); extern struct rb_node *rb_next_postorder(const struct rb_node *); /* Fast replacement of a single node without remove/rebalance/add/rebalance */ extern void rb_replace_node(struct rb_node *victim, struct rb_node *new_node, struct rb_root *root); static inline void rb_link_node(struct rb_node * node, struct rb_node * parent, struct rb_node ** rb_link) { node->__rb_parent_color = (unsigned long)parent; node->rb_left = node->rb_right = NULL; *rb_link = node; } #define rb_entry_safe(ptr, type, member) \ ({ typeof(ptr) ____ptr = (ptr); \ ____ptr ? rb_entry(____ptr, type, member) : NULL; \ }) /** * rbtree_postorder_for_each_entry_safe - iterate over rb_root in post order of * given type safe against removal of rb_node entry * * @pos: the 'type *' to use as a loop cursor. * @n: another 'type *' to use as temporary storage * @root: 'rb_root *' of the rbtree. * @field: the name of the rb_node field within 'type'. */ #define rbtree_postorder_for_each_entry_safe(pos, n, root, field) \ for (pos = rb_entry_safe(rb_first_postorder(root), typeof(*pos), field); \ pos && ({ n = rb_entry_safe(rb_next_postorder(&pos->field), \ typeof(*pos), field); 1; }); \ pos = n) #ifdef __cplusplus } #endif #endif /* _LINUX_RBTREE_H */ partclone-0.2.86/src/btrfs/rbtree_augmented.h000066400000000000000000000157511262102574200212040ustar00rootroot00000000000000/* Red Black Trees (C) 1999 Andrea Arcangeli (C) 2002 David Woodhouse (C) 2012 Michel Lespinasse This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA linux/include/linux/rbtree_augmented.h */ #ifndef _LINUX_RBTREE_AUGMENTED_H #define _LINUX_RBTREE_AUGMENTED_H #include "rbtree.h" #ifdef __cplusplus extern "C" { #endif /* * Please note - only struct rb_augment_callbacks and the prototypes for * rb_insert_augmented() and rb_erase_augmented() are intended to be public. * The rest are implementation details you are not expected to depend on. * * See Documentation/rbtree.txt for documentation and samples. */ struct rb_augment_callbacks { void (*propagate)(struct rb_node *node, struct rb_node *stop); void (*copy)(struct rb_node *old, struct rb_node *new); void (*rotate)(struct rb_node *old, struct rb_node *new); }; extern void __rb_insert_augmented(struct rb_node *node, struct rb_root *root, void (*augment_rotate)(struct rb_node *old, struct rb_node *new)); static inline void rb_insert_augmented(struct rb_node *node, struct rb_root *root, const struct rb_augment_callbacks *augment) { __rb_insert_augmented(node, root, augment->rotate); } #define RB_DECLARE_CALLBACKS(rbstatic, rbname, rbstruct, rbfield, \ rbtype, rbaugmented, rbcompute) \ static inline void \ rbname ## _propagate(struct rb_node *rb, struct rb_node *stop) \ { \ while (rb != stop) { \ rbstruct *node = rb_entry(rb, rbstruct, rbfield); \ rbtype augmented = rbcompute(node); \ if (node->rbaugmented == augmented) \ break; \ node->rbaugmented = augmented; \ rb = rb_parent(&node->rbfield); \ } \ } \ static inline void \ rbname ## _copy(struct rb_node *rb_old, struct rb_node *rb_new) \ { \ rbstruct *old = rb_entry(rb_old, rbstruct, rbfield); \ rbstruct *new = rb_entry(rb_new, rbstruct, rbfield); \ new->rbaugmented = old->rbaugmented; \ } \ static void \ rbname ## _rotate(struct rb_node *rb_old, struct rb_node *rb_new) \ { \ rbstruct *old = rb_entry(rb_old, rbstruct, rbfield); \ rbstruct *new = rb_entry(rb_new, rbstruct, rbfield); \ new->rbaugmented = old->rbaugmented; \ old->rbaugmented = rbcompute(old); \ } \ rbstatic const struct rb_augment_callbacks rbname = { \ rbname ## _propagate, rbname ## _copy, rbname ## _rotate \ }; #define RB_RED 0 #define RB_BLACK 1 #define __rb_parent(pc) ((struct rb_node *)(pc & ~3)) #define __rb_color(pc) ((pc) & 1) #define __rb_is_black(pc) __rb_color(pc) #define __rb_is_red(pc) (!__rb_color(pc)) #define rb_color(rb) __rb_color((rb)->__rb_parent_color) #define rb_is_red(rb) __rb_is_red((rb)->__rb_parent_color) #define rb_is_black(rb) __rb_is_black((rb)->__rb_parent_color) static inline void rb_set_parent(struct rb_node *rb, struct rb_node *p) { rb->__rb_parent_color = rb_color(rb) | (unsigned long)p; } static inline void rb_set_parent_color(struct rb_node *rb, struct rb_node *p, int color) { rb->__rb_parent_color = (unsigned long)p | color; } static inline void __rb_change_child(struct rb_node *old, struct rb_node *new, struct rb_node *parent, struct rb_root *root) { if (parent) { if (parent->rb_left == old) parent->rb_left = new; else parent->rb_right = new; } else root->rb_node = new; } extern void __rb_erase_color(struct rb_node *parent, struct rb_root *root, void (*augment_rotate)(struct rb_node *old, struct rb_node *new)); static __always_inline struct rb_node * __rb_erase_augmented(struct rb_node *node, struct rb_root *root, const struct rb_augment_callbacks *augment) { struct rb_node *child = node->rb_right, *tmp = node->rb_left; struct rb_node *parent, *rebalance; unsigned long pc; if (!tmp) { /* * Case 1: node to erase has no more than 1 child (easy!) * * Note that if there is one child it must be red due to 5) * and node must be black due to 4). We adjust colors locally * so as to bypass __rb_erase_color() later on. */ pc = node->__rb_parent_color; parent = __rb_parent(pc); __rb_change_child(node, child, parent, root); if (child) { child->__rb_parent_color = pc; rebalance = NULL; } else rebalance = __rb_is_black(pc) ? parent : NULL; tmp = parent; } else if (!child) { /* Still case 1, but this time the child is node->rb_left */ tmp->__rb_parent_color = pc = node->__rb_parent_color; parent = __rb_parent(pc); __rb_change_child(node, tmp, parent, root); rebalance = NULL; tmp = parent; } else { struct rb_node *successor = child, *child2; tmp = child->rb_left; if (!tmp) { /* * Case 2: node's successor is its right child * * (n) (s) * / \ / \ * (x) (s) -> (x) (c) * \ * (c) */ parent = successor; child2 = successor->rb_right; augment->copy(node, successor); } else { /* * Case 3: node's successor is leftmost under * node's right child subtree * * (n) (s) * / \ / \ * (x) (y) -> (x) (y) * / / * (p) (p) * / / * (s) (c) * \ * (c) */ do { parent = successor; successor = tmp; tmp = tmp->rb_left; } while (tmp); parent->rb_left = child2 = successor->rb_right; successor->rb_right = child; rb_set_parent(child, successor); augment->copy(node, successor); augment->propagate(parent, successor); } successor->rb_left = tmp = node->rb_left; rb_set_parent(tmp, successor); pc = node->__rb_parent_color; tmp = __rb_parent(pc); __rb_change_child(node, successor, tmp, root); if (child2) { successor->__rb_parent_color = pc; rb_set_parent_color(child2, parent, RB_BLACK); rebalance = NULL; } else { unsigned long pc2 = successor->__rb_parent_color; successor->__rb_parent_color = pc; rebalance = __rb_is_black(pc2) ? parent : NULL; } tmp = successor; } augment->propagate(tmp, NULL); return rebalance; } static __always_inline void rb_erase_augmented(struct rb_node *node, struct rb_root *root, const struct rb_augment_callbacks *augment) { struct rb_node *rebalance = __rb_erase_augmented(node, root, augment); if (rebalance) __rb_erase_color(rebalance, root, augment->rotate); } #ifdef __cplusplus } #endif #endif /* _LINUX_RBTREE_AUGMENTED_H */ partclone-0.2.86/src/btrfs/repair.c000066400000000000000000000025501262102574200171360ustar00rootroot00000000000000/* * Copyright (C) 2012 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. */ #include "ctree.h" #include "extent-cache.h" #include "utils.h" #include "repair.h" int btrfs_add_corrupt_extent_record(struct btrfs_fs_info *info, struct btrfs_key *first_key, u64 start, u64 len, int level) { int ret = 0; struct btrfs_corrupt_block *corrupt; if (!info->corrupt_blocks) return 0; corrupt = malloc(sizeof(*corrupt)); if (!corrupt) return -ENOMEM; memcpy(&corrupt->key, first_key, sizeof(*first_key)); corrupt->cache.start = start; corrupt->cache.size = len; corrupt->level = level; ret = insert_cache_extent(info->corrupt_blocks, &corrupt->cache); if (ret) free(corrupt); BUG_ON(ret && ret != -EEXIST); return ret; } partclone-0.2.86/src/btrfs/repair.h000066400000000000000000000017551262102574200171510ustar00rootroot00000000000000/* * Copyright (C) 2012 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. */ #ifndef __BTRFS_REPAIR__ #define __BTRFS_REPAIR__ struct btrfs_corrupt_block { struct cache_extent cache; struct btrfs_key key; int level; }; int btrfs_add_corrupt_extent_record(struct btrfs_fs_info *info, struct btrfs_key *first_key, u64 start, u64 len, int level); #endif partclone-0.2.86/src/btrfs/root-tree.c000066400000000000000000000116461262102574200176020ustar00rootroot00000000000000/* * Copyright (C) 2007 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. */ #include "ctree.h" #include "transaction.h" #include "disk-io.h" #include "print-tree.h" int btrfs_find_last_root(struct btrfs_root *root, u64 objectid, struct btrfs_root_item *item, struct btrfs_key *key) { struct btrfs_path *path; struct btrfs_key search_key; struct btrfs_key found_key; struct extent_buffer *l; int ret; int slot; search_key.objectid = objectid; search_key.type = BTRFS_ROOT_ITEM_KEY; search_key.offset = (u64)-1; path = btrfs_alloc_path(); BUG_ON(!path); ret = btrfs_search_slot(NULL, root, &search_key, path, 0, 0); if (ret < 0) goto out; if (path->slots[0] == 0) { ret = -ENOENT; goto out; } BUG_ON(ret == 0); l = path->nodes[0]; slot = path->slots[0] - 1; btrfs_item_key_to_cpu(l, &found_key, slot); if (found_key.objectid != objectid) { ret = -ENOENT; goto out; } read_extent_buffer(l, item, btrfs_item_ptr_offset(l, slot), sizeof(*item)); memcpy(key, &found_key, sizeof(found_key)); ret = 0; out: btrfs_free_path(path); return ret; } int btrfs_update_root(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_key *key, struct btrfs_root_item *item) { struct btrfs_path *path; struct extent_buffer *l; int ret; int slot; unsigned long ptr; u32 old_len; path = btrfs_alloc_path(); BUG_ON(!path); ret = btrfs_search_slot(trans, root, key, path, 0, 1); if (ret < 0) goto out; BUG_ON(ret != 0); l = path->nodes[0]; slot = path->slots[0]; ptr = btrfs_item_ptr_offset(l, slot); old_len = btrfs_item_size_nr(l, slot); /* * If this is the first time we update the root item which originated * from an older kernel, we need to enlarge the item size to make room * for the added fields. */ if (old_len < sizeof(*item)) { btrfs_release_path(path); ret = btrfs_search_slot(trans, root, key, path, -1, 1); if (ret < 0) { goto out; } ret = btrfs_del_item(trans, root, path); if (ret < 0) { goto out; } btrfs_release_path(path); ret = btrfs_insert_empty_item(trans, root, path, key, sizeof(*item)); if (ret < 0) { goto out; } l = path->nodes[0]; slot = path->slots[0]; ptr = btrfs_item_ptr_offset(l, slot); } /* * Update generation_v2 so at the next mount we know the new root * fields are valid. */ btrfs_set_root_generation_v2(item, btrfs_root_generation(item)); write_extent_buffer(l, item, ptr, sizeof(*item)); btrfs_mark_buffer_dirty(path->nodes[0]); out: btrfs_free_path(path); return ret; } int btrfs_insert_root(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_key *key, struct btrfs_root_item *item) { int ret; /* * Make sure generation v1 and v2 match. See update_root for details. */ btrfs_set_root_generation_v2(item, btrfs_root_generation(item)); ret = btrfs_insert_item(trans, root, key, item, sizeof(*item)); return ret; } /* * add a btrfs_root_ref item. type is either BTRFS_ROOT_REF_KEY * or BTRFS_ROOT_BACKREF_KEY. * * The dirid, sequence, name and name_len refer to the directory entry * that is referencing the root. * * For a forward ref, the root_id is the id of the tree referencing * the root and ref_id is the id of the subvol or snapshot. * * For a back ref the root_id is the id of the subvol or snapshot and * ref_id is the id of the tree referencing it. */ int btrfs_add_root_ref(struct btrfs_trans_handle *trans, struct btrfs_root *tree_root, u64 root_id, u8 type, u64 ref_id, u64 dirid, u64 sequence, const char *name, int name_len) { struct btrfs_key key; int ret; struct btrfs_path *path; struct btrfs_root_ref *ref; struct extent_buffer *leaf; unsigned long ptr; path = btrfs_alloc_path(); if (!path) return -ENOMEM; key.objectid = root_id; key.type = type; key.offset = ref_id; ret = btrfs_insert_empty_item(trans, tree_root, path, &key, sizeof(*ref) + name_len); BUG_ON(ret); leaf = path->nodes[0]; ref = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_root_ref); btrfs_set_root_ref_dirid(leaf, ref, dirid); btrfs_set_root_ref_sequence(leaf, ref, sequence); btrfs_set_root_ref_name_len(leaf, ref, name_len); ptr = (unsigned long)(ref + 1); write_extent_buffer(leaf, name, ptr, name_len); btrfs_mark_buffer_dirty(leaf); btrfs_free_path(path); return ret; } partclone-0.2.86/src/btrfs/send-stream.c000066400000000000000000000300231262102574200200720ustar00rootroot00000000000000/* * Copyright (C) 2012 Alexander Block. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. */ #include #include #include "send.h" #include "send-stream.h" #include "crc32c.h" struct btrfs_send_stream { int fd; char read_buf[BTRFS_SEND_BUF_SIZE]; int cmd; struct btrfs_cmd_header *cmd_hdr; struct btrfs_tlv_header *cmd_attrs[BTRFS_SEND_A_MAX + 1]; u32 version; struct btrfs_send_ops *ops; void *user; }; static int read_buf(struct btrfs_send_stream *s, void *buf, int len) { int ret; int pos = 0; while (pos < len) { ret = read(s->fd, (char*)buf + pos, len - pos); if (ret < 0) { ret = -errno; fprintf(stderr, "ERROR: read from stream failed. %s\n", strerror(-ret)); goto out; } if (ret == 0) { ret = 1; goto out; } pos += ret; } ret = 0; out: return ret; } /* * Reads a single command from kernel space and decodes the TLV's into * s->cmd_attrs */ static int read_cmd(struct btrfs_send_stream *s) { int ret; int cmd; int cmd_len; int tlv_type; int tlv_len; char *data; int pos; struct btrfs_tlv_header *tlv_hdr; u32 crc; u32 crc2; memset(s->cmd_attrs, 0, sizeof(s->cmd_attrs)); ret = read_buf(s, s->read_buf, sizeof(*s->cmd_hdr)); if (ret < 0) goto out; if (ret) { ret = -EINVAL; fprintf(stderr, "ERROR: unexpected EOF in stream.\n"); goto out; } s->cmd_hdr = (struct btrfs_cmd_header *)s->read_buf; cmd = le16_to_cpu(s->cmd_hdr->cmd); cmd_len = le32_to_cpu(s->cmd_hdr->len); data = s->read_buf + sizeof(*s->cmd_hdr); ret = read_buf(s, data, cmd_len); if (ret < 0) goto out; if (ret) { ret = -EINVAL; fprintf(stderr, "ERROR: unexpected EOF in stream.\n"); goto out; } crc = le32_to_cpu(s->cmd_hdr->crc); s->cmd_hdr->crc = 0; crc2 = crc32c(0, (unsigned char*)s->read_buf, sizeof(*s->cmd_hdr) + cmd_len); if (crc != crc2) { ret = -EINVAL; fprintf(stderr, "ERROR: crc32 mismatch in command.\n"); goto out; } pos = 0; while (pos < cmd_len) { tlv_hdr = (struct btrfs_tlv_header *)data; tlv_type = le16_to_cpu(tlv_hdr->tlv_type); tlv_len = le16_to_cpu(tlv_hdr->tlv_len); if (tlv_type <= 0 || tlv_type > BTRFS_SEND_A_MAX || tlv_len < 0 || tlv_len > BTRFS_SEND_BUF_SIZE) { fprintf(stderr, "ERROR: invalid tlv in cmd. " "tlv_type = %d, tlv_len = %d\n", tlv_type, tlv_len); ret = -EINVAL; goto out; } s->cmd_attrs[tlv_type] = tlv_hdr; data += sizeof(*tlv_hdr) + tlv_len; pos += sizeof(*tlv_hdr) + tlv_len; } s->cmd = cmd; ret = 0; out: return ret; } static int tlv_get(struct btrfs_send_stream *s, int attr, void **data, int *len) { int ret; struct btrfs_tlv_header *h; if (attr <= 0 || attr > BTRFS_SEND_A_MAX) { fprintf(stderr, "ERROR: invalid attribute requested. " "attr = %d\n", attr); ret = -EINVAL; goto out; } h = s->cmd_attrs[attr]; if (!h) { fprintf(stderr, "ERROR: attribute %d requested " "but not present.\n", attr); ret = -ENOENT; goto out; } *len = le16_to_cpu(h->tlv_len); *data = h + 1; ret = 0; out: return ret; } #define __TLV_GOTO_FAIL(expr) \ if ((ret = expr) < 0) \ goto tlv_get_failed; #define __TLV_DO_WHILE_GOTO_FAIL(expr) \ do { \ __TLV_GOTO_FAIL(expr) \ } while (0) #define TLV_GET(s, attr, data, len) \ __TLV_DO_WHILE_GOTO_FAIL(tlv_get(s, attr, data, len)) #define TLV_CHECK_LEN(expected, got) \ do { \ if (expected != got) { \ fprintf(stderr, "ERROR: invalid size for attribute. " \ "expected = %d, got = %d\n", \ (int)expected, (int)got); \ ret = -EINVAL; \ goto tlv_get_failed; \ } \ } while (0) #define TLV_GET_INT(s, attr, bits, v) \ do { \ __le##bits *__tmp; \ int __len; \ TLV_GET(s, attr, (void**)&__tmp, &__len); \ TLV_CHECK_LEN(sizeof(*__tmp), __len); \ *v = get_unaligned_le##bits(__tmp); \ } while (0) #define TLV_GET_U8(s, attr, v) TLV_GET_INT(s, attr, 8, v) #define TLV_GET_U16(s, attr, v) TLV_GET_INT(s, attr, 16, v) #define TLV_GET_U32(s, attr, v) TLV_GET_INT(s, attr, 32, v) #define TLV_GET_U64(s, attr, v) TLV_GET_INT(s, attr, 64, v) static int tlv_get_string(struct btrfs_send_stream *s, int attr, char **str) { int ret; void *data; int len = 0; TLV_GET(s, attr, &data, &len); *str = malloc(len + 1); if (!*str) return -ENOMEM; memcpy(*str, data, len); (*str)[len] = 0; ret = 0; tlv_get_failed: return ret; } #define TLV_GET_STRING(s, attr, str) \ __TLV_DO_WHILE_GOTO_FAIL(tlv_get_string(s, attr, str)) static int tlv_get_timespec(struct btrfs_send_stream *s, int attr, struct timespec *ts) { int ret; int len; struct btrfs_timespec *bts; TLV_GET(s, attr, (void**)&bts, &len); TLV_CHECK_LEN(sizeof(*bts), len); ts->tv_sec = le64_to_cpu(bts->sec); ts->tv_nsec = le32_to_cpu(bts->nsec); ret = 0; tlv_get_failed: return ret; } #define TLV_GET_TIMESPEC(s, attr, ts) \ __TLV_DO_WHILE_GOTO_FAIL(tlv_get_timespec(s, attr, ts)) static int tlv_get_uuid(struct btrfs_send_stream *s, int attr, u8 *uuid) { int ret; int len; void *data; TLV_GET(s, attr, &data, &len); TLV_CHECK_LEN(BTRFS_UUID_SIZE, len); memcpy(uuid, data, BTRFS_UUID_SIZE); ret = 0; tlv_get_failed: return ret; } #define TLV_GET_UUID(s, attr, uuid) \ __TLV_DO_WHILE_GOTO_FAIL(tlv_get_uuid(s, attr, uuid)) static int read_and_process_cmd(struct btrfs_send_stream *s) { int ret; char *path = NULL; char *path_to = NULL; char *clone_path = NULL; char *xattr_name = NULL; void *xattr_data = NULL; void *data = NULL; struct timespec at; struct timespec ct; struct timespec mt; u8 uuid[BTRFS_UUID_SIZE]; u8 clone_uuid[BTRFS_UUID_SIZE]; u64 tmp; u64 tmp2; u64 ctransid; u64 clone_ctransid; u64 mode; u64 dev; u64 clone_offset; u64 offset; int len; int xattr_len; ret = read_cmd(s); if (ret) goto out; switch (s->cmd) { case BTRFS_SEND_C_SUBVOL: TLV_GET_STRING(s, BTRFS_SEND_A_PATH, &path); TLV_GET_UUID(s, BTRFS_SEND_A_UUID, uuid); TLV_GET_U64(s, BTRFS_SEND_A_CTRANSID, &ctransid); ret = s->ops->subvol(path, uuid, ctransid, s->user); break; case BTRFS_SEND_C_SNAPSHOT: TLV_GET_STRING(s, BTRFS_SEND_A_PATH, &path); TLV_GET_UUID(s, BTRFS_SEND_A_UUID, uuid); TLV_GET_U64(s, BTRFS_SEND_A_CTRANSID, &ctransid); TLV_GET_UUID(s, BTRFS_SEND_A_CLONE_UUID, clone_uuid); TLV_GET_U64(s, BTRFS_SEND_A_CLONE_CTRANSID, &clone_ctransid); ret = s->ops->snapshot(path, uuid, ctransid, clone_uuid, clone_ctransid, s->user); break; case BTRFS_SEND_C_MKFILE: TLV_GET_STRING(s, BTRFS_SEND_A_PATH, &path); ret = s->ops->mkfile(path, s->user); break; case BTRFS_SEND_C_MKDIR: TLV_GET_STRING(s, BTRFS_SEND_A_PATH, &path); ret = s->ops->mkdir(path, s->user); break; case BTRFS_SEND_C_MKNOD: TLV_GET_STRING(s, BTRFS_SEND_A_PATH, &path); TLV_GET_U64(s, BTRFS_SEND_A_MODE, &mode); TLV_GET_U64(s, BTRFS_SEND_A_RDEV, &dev); ret = s->ops->mknod(path, mode, dev, s->user); break; case BTRFS_SEND_C_MKFIFO: TLV_GET_STRING(s, BTRFS_SEND_A_PATH, &path); ret = s->ops->mkfifo(path, s->user); break; case BTRFS_SEND_C_MKSOCK: TLV_GET_STRING(s, BTRFS_SEND_A_PATH, &path); ret = s->ops->mksock(path, s->user); break; case BTRFS_SEND_C_SYMLINK: TLV_GET_STRING(s, BTRFS_SEND_A_PATH, &path); TLV_GET_STRING(s, BTRFS_SEND_A_PATH_LINK, &path_to); ret = s->ops->symlink(path, path_to, s->user); break; case BTRFS_SEND_C_RENAME: TLV_GET_STRING(s, BTRFS_SEND_A_PATH, &path); TLV_GET_STRING(s, BTRFS_SEND_A_PATH_TO, &path_to); ret = s->ops->rename(path, path_to, s->user); break; case BTRFS_SEND_C_LINK: TLV_GET_STRING(s, BTRFS_SEND_A_PATH, &path); TLV_GET_STRING(s, BTRFS_SEND_A_PATH_LINK, &path_to); ret = s->ops->link(path, path_to, s->user); break; case BTRFS_SEND_C_UNLINK: TLV_GET_STRING(s, BTRFS_SEND_A_PATH, &path); ret = s->ops->unlink(path, s->user); break; case BTRFS_SEND_C_RMDIR: TLV_GET_STRING(s, BTRFS_SEND_A_PATH, &path); ret = s->ops->rmdir(path, s->user); break; case BTRFS_SEND_C_WRITE: TLV_GET_STRING(s, BTRFS_SEND_A_PATH, &path); TLV_GET_U64(s, BTRFS_SEND_A_FILE_OFFSET, &offset); TLV_GET(s, BTRFS_SEND_A_DATA, &data, &len); ret = s->ops->write(path, data, offset, len, s->user); break; case BTRFS_SEND_C_CLONE: TLV_GET_STRING(s, BTRFS_SEND_A_PATH, &path); TLV_GET_U64(s, BTRFS_SEND_A_FILE_OFFSET, &offset); TLV_GET_U64(s, BTRFS_SEND_A_CLONE_LEN, &len); TLV_GET_UUID(s, BTRFS_SEND_A_CLONE_UUID, clone_uuid); TLV_GET_U64(s, BTRFS_SEND_A_CLONE_CTRANSID, &clone_ctransid); TLV_GET_STRING(s, BTRFS_SEND_A_CLONE_PATH, &clone_path); TLV_GET_U64(s, BTRFS_SEND_A_CLONE_OFFSET, &clone_offset); ret = s->ops->clone(path, offset, len, clone_uuid, clone_ctransid, clone_path, clone_offset, s->user); break; case BTRFS_SEND_C_SET_XATTR: TLV_GET_STRING(s, BTRFS_SEND_A_PATH, &path); TLV_GET_STRING(s, BTRFS_SEND_A_XATTR_NAME, &xattr_name); TLV_GET(s, BTRFS_SEND_A_XATTR_DATA, &xattr_data, &xattr_len); ret = s->ops->set_xattr(path, xattr_name, xattr_data, xattr_len, s->user); break; case BTRFS_SEND_C_REMOVE_XATTR: TLV_GET_STRING(s, BTRFS_SEND_A_PATH, &path); TLV_GET_STRING(s, BTRFS_SEND_A_XATTR_NAME, &xattr_name); ret = s->ops->remove_xattr(path, xattr_name, s->user); break; case BTRFS_SEND_C_TRUNCATE: TLV_GET_STRING(s, BTRFS_SEND_A_PATH, &path); TLV_GET_U64(s, BTRFS_SEND_A_SIZE, &tmp); ret = s->ops->truncate(path, tmp, s->user); break; case BTRFS_SEND_C_CHMOD: TLV_GET_STRING(s, BTRFS_SEND_A_PATH, &path); TLV_GET_U64(s, BTRFS_SEND_A_MODE, &tmp); ret = s->ops->chmod(path, tmp, s->user); break; case BTRFS_SEND_C_CHOWN: TLV_GET_STRING(s, BTRFS_SEND_A_PATH, &path); TLV_GET_U64(s, BTRFS_SEND_A_UID, &tmp); TLV_GET_U64(s, BTRFS_SEND_A_GID, &tmp2); ret = s->ops->chown(path, tmp, tmp2, s->user); break; case BTRFS_SEND_C_UTIMES: TLV_GET_STRING(s, BTRFS_SEND_A_PATH, &path); TLV_GET_TIMESPEC(s, BTRFS_SEND_A_ATIME, &at); TLV_GET_TIMESPEC(s, BTRFS_SEND_A_MTIME, &mt); TLV_GET_TIMESPEC(s, BTRFS_SEND_A_CTIME, &ct); ret = s->ops->utimes(path, &at, &mt, &ct, s->user); break; case BTRFS_SEND_C_UPDATE_EXTENT: TLV_GET_STRING(s, BTRFS_SEND_A_PATH, &path); TLV_GET_U64(s, BTRFS_SEND_A_FILE_OFFSET, &offset); TLV_GET_U64(s, BTRFS_SEND_A_SIZE, &tmp); ret = s->ops->update_extent(path, offset, tmp, s->user); break; case BTRFS_SEND_C_END: ret = 1; break; } tlv_get_failed: out: free(path); free(path_to); free(clone_path); free(xattr_name); return ret; } /* * If max_errors is 0, then don't stop processing the stream if one of the * callbacks in btrfs_send_ops structure returns an error. If greater than * zero, stop after max_errors errors happened. */ int btrfs_read_and_process_send_stream(int fd, struct btrfs_send_ops *ops, void *user, int honor_end_cmd, u64 max_errors) { int ret; struct btrfs_send_stream s; struct btrfs_stream_header hdr; u64 errors = 0; int last_err = 0; s.fd = fd; s.ops = ops; s.user = user; ret = read_buf(&s, &hdr, sizeof(hdr)); if (ret < 0) goto out; if (ret) { ret = 1; goto out; } if (strcmp(hdr.magic, BTRFS_SEND_STREAM_MAGIC)) { ret = -EINVAL; fprintf(stderr, "ERROR: Unexpected header\n"); goto out; } s.version = le32_to_cpu(hdr.version); if (s.version > BTRFS_SEND_STREAM_VERSION) { ret = -EINVAL; fprintf(stderr, "ERROR: Stream version %d not supported. " "Please upgrade btrfs-progs\n", s.version); goto out; } while (1) { ret = read_and_process_cmd(&s); if (ret < 0) { last_err = ret; errors++; if (max_errors > 0 && errors >= max_errors) goto out; } else if (ret > 0) { if (!honor_end_cmd) ret = 0; goto out; } } out: if (last_err && !ret) ret = last_err; return ret; } partclone-0.2.86/src/btrfs/send-stream.h000066400000000000000000000051771262102574200201130ustar00rootroot00000000000000/* * Copyright (C) 2012 Alexander Block. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. */ #ifndef SEND_STREAM_H_ #define SEND_STREAM_H_ /* * NOTE: this file is public API, any incompatible change has to update * library version */ #ifdef __cplusplus extern "C" { #endif struct btrfs_send_ops { int (*subvol)(const char *path, const u8 *uuid, u64 ctransid, void *user); int (*snapshot)(const char *path, const u8 *uuid, u64 ctransid, const u8 *parent_uuid, u64 parent_ctransid, void *user); int (*mkfile)(const char *path, void *user); int (*mkdir)(const char *path, void *user); int (*mknod)(const char *path, u64 mode, u64 dev, void *user); int (*mkfifo)(const char *path, void *user); int (*mksock)(const char *path, void *user); int (*symlink)(const char *path, const char *lnk, void *user); int (*rename)(const char *from, const char *to, void *user); int (*link)(const char *path, const char *lnk, void *user); int (*unlink)(const char *path, void *user); int (*rmdir)(const char *path, void *user); int (*write)(const char *path, const void *data, u64 offset, u64 len, void *user); int (*clone)(const char *path, u64 offset, u64 len, const u8 *clone_uuid, u64 clone_ctransid, const char *clone_path, u64 clone_offset, void *user); int (*set_xattr)(const char *path, const char *name, const void *data, int len, void *user); int (*remove_xattr)(const char *path, const char *name, void *user); int (*truncate)(const char *path, u64 size, void *user); int (*chmod)(const char *path, u64 mode, void *user); int (*chown)(const char *path, u64 uid, u64 gid, void *user); int (*utimes)(const char *path, struct timespec *at, struct timespec *mt, struct timespec *ct, void *user); int (*update_extent)(const char *path, u64 offset, u64 len, void *user); }; int btrfs_read_and_process_send_stream(int fd, struct btrfs_send_ops *ops, void *user, int honor_end_cmd, u64 max_errors); #ifdef __cplusplus } #endif #endif /* SEND_STREAM_H_ */ partclone-0.2.86/src/btrfs/send-utils.c000066400000000000000000000450711262102574200177500ustar00rootroot00000000000000/* * Copyright (C) 2012 Alexander Block. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. */ #include #include #include #include #include "ctree.h" #include "send-utils.h" #include "ioctl.h" #include "btrfs-list.h" static int btrfs_subvolid_resolve_sub(int fd, char *path, size_t *path_len, u64 subvol_id); static int btrfs_get_root_id_by_sub_path(int mnt_fd, const char *sub_path, u64 *root_id) { int ret; int subvol_fd; subvol_fd = openat(mnt_fd, sub_path, O_RDONLY); if (subvol_fd < 0) { ret = -errno; fprintf(stderr, "ERROR: open %s failed. %s\n", sub_path, strerror(-ret)); return ret; } ret = btrfs_list_get_path_rootid(subvol_fd, root_id); close(subvol_fd); return ret; } static int btrfs_read_root_item_raw(int mnt_fd, u64 root_id, size_t buf_len, u32 *read_len, void *buf) { int ret; struct btrfs_ioctl_search_args args; struct btrfs_ioctl_search_key *sk = &args.key; struct btrfs_ioctl_search_header *sh; unsigned long off = 0; int found = 0; int i; *read_len = 0; memset(&args, 0, sizeof(args)); sk->tree_id = BTRFS_ROOT_TREE_OBJECTID; /* * there may be more than one ROOT_ITEM key if there are * snapshots pending deletion, we have to loop through * them. */ sk->min_objectid = root_id; sk->max_objectid = root_id; sk->max_type = BTRFS_ROOT_ITEM_KEY; sk->min_type = BTRFS_ROOT_ITEM_KEY; sk->max_offset = (u64)-1; sk->max_transid = (u64)-1; sk->nr_items = 4096; while (1) { ret = ioctl(mnt_fd, BTRFS_IOC_TREE_SEARCH, &args); if (ret < 0) { fprintf(stderr, "ERROR: can't perform the search - %s\n", strerror(errno)); return 0; } /* the ioctl returns the number of item it found in nr_items */ if (sk->nr_items == 0) break; off = 0; for (i = 0; i < sk->nr_items; i++) { struct btrfs_root_item *item; sh = (struct btrfs_ioctl_search_header *)(args.buf + off); off += sizeof(*sh); item = (struct btrfs_root_item *)(args.buf + off); off += sh->len; sk->min_objectid = sh->objectid; sk->min_type = sh->type; sk->min_offset = sh->offset; if (sh->objectid > root_id) break; if (sh->objectid == root_id && sh->type == BTRFS_ROOT_ITEM_KEY) { if (sh->len > buf_len) { /* btrfs-progs is too old for kernel */ fprintf(stderr, "ERROR: buf for read_root_item_raw() is too small, get newer btrfs tools!\n"); return -EOVERFLOW; } memcpy(buf, item, sh->len); *read_len = sh->len; found = 1; } } if (sk->min_offset < (u64)-1) sk->min_offset++; else break; if (sk->min_type != BTRFS_ROOT_ITEM_KEY || sk->min_objectid != root_id) break; } return found ? 0 : -ENOENT; } /* * Read a root item from the tree. In case we detect a root item smaller then * sizeof(root_item), we know it's an old version of the root structure and * initialize all new fields to zero. The same happens if we detect mismatching * generation numbers as then we know the root was once mounted with an older * kernel that was not aware of the root item structure change. */ static int btrfs_read_root_item(int mnt_fd, u64 root_id, struct btrfs_root_item *item) { int ret; u32 read_len; ret = btrfs_read_root_item_raw(mnt_fd, root_id, sizeof(*item), &read_len, item); if (ret) return ret; if (read_len < sizeof(*item) || btrfs_root_generation(item) != btrfs_root_generation_v2(item)) memset(&item->generation_v2, 0, sizeof(*item) - offsetof(struct btrfs_root_item, generation_v2)); return 0; } #ifdef BTRFS_COMPAT_SEND_NO_UUID_TREE static struct rb_node *tree_insert(struct rb_root *root, struct subvol_info *si, enum subvol_search_type type) { struct rb_node **p = &root->rb_node; struct rb_node *parent = NULL; struct subvol_info *entry; __s64 comp; while (*p) { parent = *p; if (type == subvol_search_by_received_uuid) { entry = rb_entry(parent, struct subvol_info, rb_received_node); comp = memcmp(entry->received_uuid, si->received_uuid, BTRFS_UUID_SIZE); if (!comp) { if (entry->stransid < si->stransid) comp = -1; else if (entry->stransid > si->stransid) comp = 1; else comp = 0; } } else if (type == subvol_search_by_uuid) { entry = rb_entry(parent, struct subvol_info, rb_local_node); comp = memcmp(entry->uuid, si->uuid, BTRFS_UUID_SIZE); } else if (type == subvol_search_by_root_id) { entry = rb_entry(parent, struct subvol_info, rb_root_id_node); comp = entry->root_id - si->root_id; } else if (type == subvol_search_by_path) { entry = rb_entry(parent, struct subvol_info, rb_path_node); comp = strcmp(entry->path, si->path); } else { BUG(); } if (comp < 0) p = &(*p)->rb_left; else if (comp > 0) p = &(*p)->rb_right; else return parent; } if (type == subvol_search_by_received_uuid) { rb_link_node(&si->rb_received_node, parent, p); rb_insert_color(&si->rb_received_node, root); } else if (type == subvol_search_by_uuid) { rb_link_node(&si->rb_local_node, parent, p); rb_insert_color(&si->rb_local_node, root); } else if (type == subvol_search_by_root_id) { rb_link_node(&si->rb_root_id_node, parent, p); rb_insert_color(&si->rb_root_id_node, root); } else if (type == subvol_search_by_path) { rb_link_node(&si->rb_path_node, parent, p); rb_insert_color(&si->rb_path_node, root); } return NULL; } #endif int btrfs_subvolid_resolve(int fd, char *path, size_t path_len, u64 subvol_id) { if (path_len < 1) return -EOVERFLOW; path[0] = '\0'; path_len--; path[path_len] = '\0'; return btrfs_subvolid_resolve_sub(fd, path, &path_len, subvol_id); } static int btrfs_subvolid_resolve_sub(int fd, char *path, size_t *path_len, u64 subvol_id) { int ret; struct btrfs_ioctl_search_args search_arg; struct btrfs_ioctl_ino_lookup_args ino_lookup_arg; struct btrfs_ioctl_search_header *search_header; struct btrfs_root_ref *backref_item; if (subvol_id == BTRFS_FS_TREE_OBJECTID) { if (*path_len < 1) return -EOVERFLOW; *path = '\0'; (*path_len)--; return 0; } memset(&search_arg, 0, sizeof(search_arg)); search_arg.key.tree_id = BTRFS_ROOT_TREE_OBJECTID; search_arg.key.min_objectid = subvol_id; search_arg.key.max_objectid = subvol_id; search_arg.key.min_type = BTRFS_ROOT_BACKREF_KEY; search_arg.key.max_type = BTRFS_ROOT_BACKREF_KEY; search_arg.key.max_offset = (u64)-1; search_arg.key.max_transid = (u64)-1; search_arg.key.nr_items = 1; ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &search_arg); if (ret) { fprintf(stderr, "ioctl(BTRFS_IOC_TREE_SEARCH, subvol_id %llu) ret=%d, error: %s\n", (unsigned long long)subvol_id, ret, strerror(errno)); return ret; } if (search_arg.key.nr_items < 1) { fprintf(stderr, "failed to lookup subvol_id %llu!\n", (unsigned long long)subvol_id); return -ENOENT; } search_header = (struct btrfs_ioctl_search_header *)search_arg.buf; backref_item = (struct btrfs_root_ref *)(search_header + 1); if (search_header->offset != BTRFS_FS_TREE_OBJECTID) { int sub_ret; sub_ret = btrfs_subvolid_resolve_sub(fd, path, path_len, search_header->offset); if (sub_ret) return sub_ret; if (*path_len < 1) return -EOVERFLOW; strcat(path, "/"); (*path_len)--; } if (btrfs_stack_root_ref_dirid(backref_item) != BTRFS_FIRST_FREE_OBJECTID) { int len; memset(&ino_lookup_arg, 0, sizeof(ino_lookup_arg)); ino_lookup_arg.treeid = search_header->offset; ino_lookup_arg.objectid = btrfs_stack_root_ref_dirid(backref_item); ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &ino_lookup_arg); if (ret) { fprintf(stderr, "ioctl(BTRFS_IOC_INO_LOOKUP) ret=%d, error: %s\n", ret, strerror(errno)); return ret; } len = strlen(ino_lookup_arg.name); if (*path_len < len) return -EOVERFLOW; strcat(path, ino_lookup_arg.name); (*path_len) -= len; } if (*path_len < btrfs_stack_root_ref_name_len(backref_item)) return -EOVERFLOW; strncat(path, (char *)(backref_item + 1), btrfs_stack_root_ref_name_len(backref_item)); (*path_len) -= btrfs_stack_root_ref_name_len(backref_item); return 0; } #ifdef BTRFS_COMPAT_SEND_NO_UUID_TREE static int count_bytes(void *buf, int len, char b) { int cnt = 0; int i; for (i = 0; i < len; i++) { if (((char *)buf)[i] == b) cnt++; } return cnt; } void subvol_uuid_search_add(struct subvol_uuid_search *s, struct subvol_info *si) { int cnt; tree_insert(&s->root_id_subvols, si, subvol_search_by_root_id); tree_insert(&s->path_subvols, si, subvol_search_by_path); cnt = count_bytes(si->uuid, BTRFS_UUID_SIZE, 0); if (cnt != BTRFS_UUID_SIZE) tree_insert(&s->local_subvols, si, subvol_search_by_uuid); cnt = count_bytes(si->received_uuid, BTRFS_UUID_SIZE, 0); if (cnt != BTRFS_UUID_SIZE) tree_insert(&s->received_subvols, si, subvol_search_by_received_uuid); } static struct subvol_info *tree_search(struct rb_root *root, u64 root_id, const u8 *uuid, u64 stransid, const char *path, enum subvol_search_type type) { struct rb_node *n = root->rb_node; struct subvol_info *entry; __s64 comp; while (n) { if (type == subvol_search_by_received_uuid) { entry = rb_entry(n, struct subvol_info, rb_received_node); comp = memcmp(entry->received_uuid, uuid, BTRFS_UUID_SIZE); if (!comp) { if (entry->stransid < stransid) comp = -1; else if (entry->stransid > stransid) comp = 1; else comp = 0; } } else if (type == subvol_search_by_uuid) { entry = rb_entry(n, struct subvol_info, rb_local_node); comp = memcmp(entry->uuid, uuid, BTRFS_UUID_SIZE); } else if (type == subvol_search_by_root_id) { entry = rb_entry(n, struct subvol_info, rb_root_id_node); comp = entry->root_id - root_id; } else if (type == subvol_search_by_path) { entry = rb_entry(n, struct subvol_info, rb_path_node); comp = strcmp(entry->path, path); } else { BUG(); } if (comp < 0) n = n->rb_left; else if (comp > 0) n = n->rb_right; else return entry; } return NULL; } /* * this function will be only called if kernel dosen't support uuid tree. */ static struct subvol_info *subvol_uuid_search_old(struct subvol_uuid_search *s, u64 root_id, const u8 *uuid, u64 transid, const char *path, enum subvol_search_type type) { struct rb_root *root; if (type == subvol_search_by_received_uuid) root = &s->received_subvols; else if (type == subvol_search_by_uuid) root = &s->local_subvols; else if (type == subvol_search_by_root_id) root = &s->root_id_subvols; else if (type == subvol_search_by_path) root = &s->path_subvols; else return NULL; return tree_search(root, root_id, uuid, transid, path, type); } #else void subvol_uuid_search_add(struct subvol_uuid_search *s, struct subvol_info *si) { if (si) { free(si->path); free(si); } } #endif struct subvol_info *subvol_uuid_search(struct subvol_uuid_search *s, u64 root_id, const u8 *uuid, u64 transid, const char *path, enum subvol_search_type type) { int ret = 0; struct btrfs_root_item root_item; struct subvol_info *info = NULL; #ifdef BTRFS_COMPAT_SEND_NO_UUID_TREE if (!s->uuid_tree_existed) return subvol_uuid_search_old(s, root_id, uuid, transid, path, type); #endif switch (type) { case subvol_search_by_received_uuid: ret = btrfs_lookup_uuid_received_subvol_item(s->mnt_fd, uuid, &root_id); break; case subvol_search_by_uuid: ret = btrfs_lookup_uuid_subvol_item(s->mnt_fd, uuid, &root_id); break; case subvol_search_by_root_id: break; case subvol_search_by_path: ret = btrfs_get_root_id_by_sub_path(s->mnt_fd, path, &root_id); break; default: ret = -EINVAL; break; } if (ret) goto out; ret = btrfs_read_root_item(s->mnt_fd, root_id, &root_item); if (ret) goto out; info = calloc(1, sizeof(*info)); info->root_id = root_id; memcpy(info->uuid, root_item.uuid, BTRFS_UUID_SIZE); memcpy(info->received_uuid, root_item.received_uuid, BTRFS_UUID_SIZE); memcpy(info->parent_uuid, root_item.parent_uuid, BTRFS_UUID_SIZE); info->ctransid = btrfs_root_ctransid(&root_item); info->otransid = btrfs_root_otransid(&root_item); info->stransid = btrfs_root_stransid(&root_item); info->rtransid = btrfs_root_rtransid(&root_item); if (type == subvol_search_by_path) { info->path = strdup(path); } else { info->path = malloc(BTRFS_PATH_NAME_MAX); ret = btrfs_subvolid_resolve(s->mnt_fd, info->path, BTRFS_PATH_NAME_MAX, root_id); } out: if (ret && info) { free(info->path); free(info); info = NULL; } return info; } #ifdef BTRFS_COMPAT_SEND_NO_UUID_TREE static int is_uuid_tree_supported(int fd) { int ret; struct btrfs_ioctl_search_args args; struct btrfs_ioctl_search_key *sk = &args.key; memset(&args, 0, sizeof(args)); sk->tree_id = BTRFS_ROOT_TREE_OBJECTID; sk->min_objectid = BTRFS_UUID_TREE_OBJECTID; sk->max_objectid = BTRFS_UUID_TREE_OBJECTID; sk->max_type = BTRFS_ROOT_ITEM_KEY; sk->min_type = BTRFS_ROOT_ITEM_KEY; sk->max_offset = (u64)-1; sk->max_transid = (u64)-1; sk->nr_items = 1; ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args); if (ret < 0) return ret; /* the ioctl returns the number of item it found in nr_items */ if (sk->nr_items == 0) return 0; return 1; } /* * this function is mainly used to read all root items * it will be only used when we use older kernel which uuid * tree is not supported yet */ int subvol_uuid_search_init(int mnt_fd, struct subvol_uuid_search *s) { int ret; struct btrfs_ioctl_search_args args; struct btrfs_ioctl_search_key *sk = &args.key; struct btrfs_ioctl_search_header *sh; struct btrfs_root_item *root_item_ptr; struct btrfs_root_item root_item = {}; struct subvol_info *si = NULL; int root_item_valid = 0; unsigned long off = 0; int i; int e; char *path; s->mnt_fd = mnt_fd; s->root_id_subvols = RB_ROOT; s->local_subvols = RB_ROOT; s->received_subvols = RB_ROOT; s->path_subvols = RB_ROOT; ret = is_uuid_tree_supported(mnt_fd); if (ret < 0) { fprintf(stderr, "ERROR: check if we support uuid tree fails - %s\n", strerror(errno)); return ret; } else if (ret) { /* uuid tree is supported */ s->uuid_tree_existed = 1; return 0; } memset(&args, 0, sizeof(args)); sk->tree_id = BTRFS_ROOT_TREE_OBJECTID; sk->max_objectid = (u64)-1; sk->max_offset = (u64)-1; sk->max_transid = (u64)-1; sk->min_type = BTRFS_ROOT_ITEM_KEY; sk->max_type = BTRFS_ROOT_BACKREF_KEY; sk->nr_items = 4096; while (1) { ret = ioctl(mnt_fd, BTRFS_IOC_TREE_SEARCH, &args); e = errno; if (ret < 0) { fprintf(stderr, "ERROR: can't perform the search - %s\n", strerror(e)); return ret; } if (sk->nr_items == 0) break; off = 0; for (i = 0; i < sk->nr_items; i++) { sh = (struct btrfs_ioctl_search_header *)(args.buf + off); off += sizeof(*sh); if ((sh->objectid != 5 && sh->objectid < BTRFS_FIRST_FREE_OBJECTID) || sh->objectid > BTRFS_LAST_FREE_OBJECTID) goto skip; if (sh->type == BTRFS_ROOT_ITEM_KEY) { /* older kernels don't have uuids+times */ if (sh->len < sizeof(root_item)) { root_item_valid = 0; goto skip; } root_item_ptr = (struct btrfs_root_item *) (args.buf + off); memcpy(&root_item, root_item_ptr, sizeof(root_item)); root_item_valid = 1; } else if (sh->type == BTRFS_ROOT_BACKREF_KEY || root_item_valid) { if (!root_item_valid) goto skip; path = btrfs_list_path_for_root(mnt_fd, sh->objectid); if (!path) path = strdup(""); if (IS_ERR(path)) { ret = PTR_ERR(path); fprintf(stderr, "ERROR: unable to " "resolve path " "for root %llu\n", sh->objectid); goto out; } si = calloc(1, sizeof(*si)); si->root_id = sh->objectid; memcpy(si->uuid, root_item.uuid, BTRFS_UUID_SIZE); memcpy(si->parent_uuid, root_item.parent_uuid, BTRFS_UUID_SIZE); memcpy(si->received_uuid, root_item.received_uuid, BTRFS_UUID_SIZE); si->ctransid = btrfs_root_ctransid(&root_item); si->otransid = btrfs_root_otransid(&root_item); si->stransid = btrfs_root_stransid(&root_item); si->rtransid = btrfs_root_rtransid(&root_item); si->path = path; subvol_uuid_search_add(s, si); root_item_valid = 0; } else { goto skip; } skip: off += sh->len; /* * record the mins in sk so we can make sure the * next search doesn't repeat this root */ sk->min_objectid = sh->objectid; sk->min_offset = sh->offset; sk->min_type = sh->type; } sk->nr_items = 4096; if (sk->min_offset < (u64)-1) sk->min_offset++; else if (sk->min_objectid < (u64)-1) { sk->min_objectid++; sk->min_offset = 0; sk->min_type = 0; } else break; } out: return ret; } void subvol_uuid_search_finit(struct subvol_uuid_search *s) { struct rb_root *root = &s->root_id_subvols; struct rb_node *node; if (!s->uuid_tree_existed) return; while ((node = rb_first(root))) { struct subvol_info *entry = rb_entry(node, struct subvol_info, rb_root_id_node); free(entry->path); rb_erase(node, root); free(entry); } s->root_id_subvols = RB_ROOT; s->local_subvols = RB_ROOT; s->received_subvols = RB_ROOT; s->path_subvols = RB_ROOT; } #else int subvol_uuid_search_init(int mnt_fd, struct subvol_uuid_search *s) { s->mnt_fd = mnt_fd; return 0; } void subvol_uuid_search_finit(struct subvol_uuid_search *s) { } #endif char *path_cat(const char *p1, const char *p2) { int p1_len = strlen(p1); int p2_len = strlen(p2); char *new = malloc(p1_len + p2_len + 2); if (p1_len && p1[p1_len - 1] == '/') p1_len--; if (p2_len && p2[p2_len - 1] == '/') p2_len--; sprintf(new, "%.*s/%.*s", p1_len, p1, p2_len, p2); return new; } char *path_cat3(const char *p1, const char *p2, const char *p3) { int p1_len = strlen(p1); int p2_len = strlen(p2); int p3_len = strlen(p3); char *new = malloc(p1_len + p2_len + p3_len + 3); if (p1_len && p1[p1_len - 1] == '/') p1_len--; if (p2_len && p2[p2_len - 1] == '/') p2_len--; if (p3_len && p3[p3_len - 1] == '/') p3_len--; sprintf(new, "%.*s/%.*s/%.*s", p1_len, p1, p2_len, p2, p3_len, p3); return new; } partclone-0.2.86/src/btrfs/send-utils.h000066400000000000000000000050351262102574200177510ustar00rootroot00000000000000/* * Copyright (C) 2012 Alexander Block. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. */ #ifndef SEND_UTILS_H_ #define SEND_UTILS_H_ #if BTRFS_FLAT_INCLUDES #include "ctree.h" #include "rbtree.h" #else #include #include #endif /* BTRFS_FLAT_INCLUDES */ #ifdef __cplusplus extern "C" { #endif /* * Compatibility code for kernels < 3.12; the UUID tree is not available there * and we have to do the slow search. This should be deprecated someday. */ #define BTRFS_COMPAT_SEND_NO_UUID_TREE 1 enum subvol_search_type { subvol_search_by_root_id, subvol_search_by_uuid, subvol_search_by_received_uuid, subvol_search_by_path, }; struct subvol_info { #ifdef BTRFS_COMPAT_SEND_NO_UUID_TREE struct rb_node rb_root_id_node; struct rb_node rb_local_node; struct rb_node rb_received_node; struct rb_node rb_path_node; #endif u64 root_id; u8 uuid[BTRFS_UUID_SIZE]; u8 parent_uuid[BTRFS_UUID_SIZE]; u8 received_uuid[BTRFS_UUID_SIZE]; u64 ctransid; u64 otransid; u64 stransid; u64 rtransid; char *path; }; struct subvol_uuid_search { int mnt_fd; #ifdef BTRFS_COMPAT_SEND_NO_UUID_TREE int uuid_tree_existed; struct rb_root root_id_subvols; struct rb_root local_subvols; struct rb_root received_subvols; struct rb_root path_subvols; #endif }; int subvol_uuid_search_init(int mnt_fd, struct subvol_uuid_search *s); void subvol_uuid_search_finit(struct subvol_uuid_search *s); struct subvol_info *subvol_uuid_search(struct subvol_uuid_search *s, u64 root_id, const u8 *uuid, u64 transid, const char *path, enum subvol_search_type type); void subvol_uuid_search_add(struct subvol_uuid_search *s, struct subvol_info *si); int btrfs_subvolid_resolve(int fd, char *path, size_t path_len, u64 subvol_id); char *path_cat(const char *p1, const char *p2); char *path_cat3(const char *p1, const char *p2, const char *p3); #ifdef __cplusplus } #endif #endif /* SEND_UTILS_H_ */ partclone-0.2.86/src/btrfs/send.h000066400000000000000000000057341262102574200166210ustar00rootroot00000000000000/* * Copyright (C) 2012 Alexander Block. All rights reserved. * Copyright (C) 2012 STRATO. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. */ #include "ctree.h" #ifdef __cplusplus extern "C" { #endif #define BTRFS_SEND_STREAM_MAGIC "btrfs-stream" #define BTRFS_SEND_STREAM_VERSION 1 #define BTRFS_SEND_BUF_SIZE (1024 * 64) #define BTRFS_SEND_READ_SIZE (1024 * 48) enum btrfs_tlv_type { BTRFS_TLV_U8, BTRFS_TLV_U16, BTRFS_TLV_U32, BTRFS_TLV_U64, BTRFS_TLV_BINARY, BTRFS_TLV_STRING, BTRFS_TLV_UUID, BTRFS_TLV_TIMESPEC, }; struct btrfs_stream_header { char magic[sizeof(BTRFS_SEND_STREAM_MAGIC)]; __le32 version; } __attribute__ ((__packed__)); struct btrfs_cmd_header { /* len excluding the header */ __le32 len; __le16 cmd; /* crc including the header with zero crc field */ __le32 crc; } __attribute__ ((__packed__)); struct btrfs_tlv_header { __le16 tlv_type; /* len excluding the header */ __le16 tlv_len; } __attribute__ ((__packed__)); /* commands */ enum btrfs_send_cmd { BTRFS_SEND_C_UNSPEC, BTRFS_SEND_C_SUBVOL, BTRFS_SEND_C_SNAPSHOT, BTRFS_SEND_C_MKFILE, BTRFS_SEND_C_MKDIR, BTRFS_SEND_C_MKNOD, BTRFS_SEND_C_MKFIFO, BTRFS_SEND_C_MKSOCK, BTRFS_SEND_C_SYMLINK, BTRFS_SEND_C_RENAME, BTRFS_SEND_C_LINK, BTRFS_SEND_C_UNLINK, BTRFS_SEND_C_RMDIR, BTRFS_SEND_C_SET_XATTR, BTRFS_SEND_C_REMOVE_XATTR, BTRFS_SEND_C_WRITE, BTRFS_SEND_C_CLONE, BTRFS_SEND_C_TRUNCATE, BTRFS_SEND_C_CHMOD, BTRFS_SEND_C_CHOWN, BTRFS_SEND_C_UTIMES, BTRFS_SEND_C_END, BTRFS_SEND_C_UPDATE_EXTENT, __BTRFS_SEND_C_MAX, }; #define BTRFS_SEND_C_MAX (__BTRFS_SEND_C_MAX - 1) /* attributes in send stream */ enum { BTRFS_SEND_A_UNSPEC, BTRFS_SEND_A_UUID, BTRFS_SEND_A_CTRANSID, BTRFS_SEND_A_INO, BTRFS_SEND_A_SIZE, BTRFS_SEND_A_MODE, BTRFS_SEND_A_UID, BTRFS_SEND_A_GID, BTRFS_SEND_A_RDEV, BTRFS_SEND_A_CTIME, BTRFS_SEND_A_MTIME, BTRFS_SEND_A_ATIME, BTRFS_SEND_A_OTIME, BTRFS_SEND_A_XATTR_NAME, BTRFS_SEND_A_XATTR_DATA, BTRFS_SEND_A_PATH, BTRFS_SEND_A_PATH_TO, BTRFS_SEND_A_PATH_LINK, BTRFS_SEND_A_FILE_OFFSET, BTRFS_SEND_A_DATA, BTRFS_SEND_A_CLONE_UUID, BTRFS_SEND_A_CLONE_CTRANSID, BTRFS_SEND_A_CLONE_PATH, BTRFS_SEND_A_CLONE_OFFSET, BTRFS_SEND_A_CLONE_LEN, __BTRFS_SEND_A_MAX, }; #define BTRFS_SEND_A_MAX (__BTRFS_SEND_A_MAX - 1) #ifdef __KERNEL__ long btrfs_ioctl_send(struct file *mnt_file, void __user *arg); #endif #ifdef __cplusplus } #endif partclone-0.2.86/src/btrfs/transaction.h000066400000000000000000000033411262102574200202050ustar00rootroot00000000000000/* * Copyright (C) 2007 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. */ #ifndef __TRANSACTION__ #define __TRANSACTION__ struct btrfs_trans_handle { u64 transid; u64 alloc_exclude_start; u64 alloc_exclude_nr; unsigned long blocks_reserved; unsigned long blocks_used; struct btrfs_block_group_cache *block_group; }; static inline struct btrfs_trans_handle * btrfs_start_transaction(struct btrfs_root *root, int num_blocks) { struct btrfs_fs_info *fs_info = root->fs_info; struct btrfs_trans_handle *h = malloc(sizeof(*h)); BUG_ON(!h); BUG_ON(root->commit_root); BUG_ON(fs_info->running_transaction); fs_info->running_transaction = h; fs_info->generation++; h->transid = fs_info->generation; h->alloc_exclude_start = 0; h->alloc_exclude_nr = 0; h->blocks_reserved = num_blocks; h->blocks_used = 0; h->block_group = NULL; root->last_trans = h->transid; root->commit_root = root->node; extent_buffer_get(root->node); return h; } static inline void btrfs_free_transaction(struct btrfs_root *root, struct btrfs_trans_handle *handle) { memset(handle, 0, sizeof(*handle)); free(handle); } #endif partclone-0.2.86/src/btrfs/ulist.c000066400000000000000000000144351262102574200170210ustar00rootroot00000000000000/* * Copyright (C) 2011 STRATO AG * written by Arne Jansen * Distributed under the GNU GPL license version 2. */ //#include #include #include "kerncompat.h" #include "ulist.h" #include "ctree.h" /* * ulist is a generic data structure to hold a collection of unique u64 * values. The only operations it supports is adding to the list and * enumerating it. * It is possible to store an auxiliary value along with the key. * * A sample usage for ulists is the enumeration of directed graphs without * visiting a node twice. The pseudo-code could look like this: * * ulist = ulist_alloc(); * ulist_add(ulist, root); * ULIST_ITER_INIT(&uiter); * * while ((elem = ulist_next(ulist, &uiter)) { * for (all child nodes n in elem) * ulist_add(ulist, n); * do something useful with the node; * } * ulist_free(ulist); * * This assumes the graph nodes are adressable by u64. This stems from the * usage for tree enumeration in btrfs, where the logical addresses are * 64 bit. * * It is also useful for tree enumeration which could be done elegantly * recursively, but is not possible due to kernel stack limitations. The * loop would be similar to the above. */ /** * ulist_init - freshly initialize a ulist * @ulist: the ulist to initialize * * Note: don't use this function to init an already used ulist, use * ulist_reinit instead. */ void ulist_init(struct ulist *ulist) { INIT_LIST_HEAD(&ulist->nodes); ulist->root = RB_ROOT; ulist->nnodes = 0; } /** * ulist_fini - free up additionally allocated memory for the ulist * @ulist: the ulist from which to free the additional memory * * This is useful in cases where the base 'struct ulist' has been statically * allocated. */ static void ulist_fini(struct ulist *ulist) { struct ulist_node *node; struct ulist_node *next; list_for_each_entry_safe(node, next, &ulist->nodes, list) { kfree(node); } ulist->root = RB_ROOT; INIT_LIST_HEAD(&ulist->nodes); } /** * ulist_reinit - prepare a ulist for reuse * @ulist: ulist to be reused * * Free up all additional memory allocated for the list elements and reinit * the ulist. */ void ulist_reinit(struct ulist *ulist) { ulist_fini(ulist); ulist_init(ulist); } /** * ulist_alloc - dynamically allocate a ulist * @gfp_mask: allocation flags to for base allocation * * The allocated ulist will be returned in an initialized state. */ struct ulist *ulist_alloc(gfp_t gfp_mask) { struct ulist *ulist = kmalloc(sizeof(*ulist), gfp_mask); if (!ulist) return NULL; ulist_init(ulist); return ulist; } /** * ulist_free - free dynamically allocated ulist * @ulist: ulist to free * * It is not necessary to call ulist_fini before. */ void ulist_free(struct ulist *ulist) { if (!ulist) return; ulist_fini(ulist); kfree(ulist); } static struct ulist_node *ulist_rbtree_search(struct ulist *ulist, u64 val) { struct rb_node *n = ulist->root.rb_node; struct ulist_node *u = NULL; while (n) { u = rb_entry(n, struct ulist_node, rb_node); if (u->val < val) n = n->rb_right; else if (u->val > val) n = n->rb_left; else return u; } return NULL; } static int ulist_rbtree_insert(struct ulist *ulist, struct ulist_node *ins) { struct rb_node **p = &ulist->root.rb_node; struct rb_node *parent = NULL; struct ulist_node *cur = NULL; while (*p) { parent = *p; cur = rb_entry(parent, struct ulist_node, rb_node); if (cur->val < ins->val) p = &(*p)->rb_right; else if (cur->val > ins->val) p = &(*p)->rb_left; else return -EEXIST; } rb_link_node(&ins->rb_node, parent, p); rb_insert_color(&ins->rb_node, &ulist->root); return 0; } /** * ulist_add - add an element to the ulist * @ulist: ulist to add the element to * @val: value to add to ulist * @aux: auxiliary value to store along with val * @gfp_mask: flags to use for allocation * * Note: locking must be provided by the caller. In case of rwlocks write * locking is needed * * Add an element to a ulist. The @val will only be added if it doesn't * already exist. If it is added, the auxiliary value @aux is stored along with * it. In case @val already exists in the ulist, @aux is ignored, even if * it differs from the already stored value. * * ulist_add returns 0 if @val already exists in ulist and 1 if @val has been * inserted. * In case of allocation failure -ENOMEM is returned and the ulist stays * unaltered. */ int ulist_add(struct ulist *ulist, u64 val, u64 aux, gfp_t gfp_mask) { return ulist_add_merge(ulist, val, aux, NULL, gfp_mask); } int ulist_add_merge(struct ulist *ulist, u64 val, u64 aux, u64 *old_aux, gfp_t gfp_mask) { int ret; struct ulist_node *node; node = ulist_rbtree_search(ulist, val); if (node) { if (old_aux) *old_aux = node->aux; return 0; } node = kmalloc(sizeof(*node), gfp_mask); if (!node) return -ENOMEM; node->val = val; node->aux = aux; #ifdef CONFIG_BTRFS_DEBUG node->seqnum = ulist->nnodes; #endif ret = ulist_rbtree_insert(ulist, node); ASSERT(!ret); list_add_tail(&node->list, &ulist->nodes); ulist->nnodes++; return 1; } /** * ulist_next - iterate ulist * @ulist: ulist to iterate * @uiter: iterator variable, initialized with ULIST_ITER_INIT(&iterator) * * Note: locking must be provided by the caller. In case of rwlocks only read * locking is needed * * This function is used to iterate an ulist. * It returns the next element from the ulist or %NULL when the * end is reached. No guarantee is made with respect to the order in which * the elements are returned. They might neither be returned in order of * addition nor in ascending order. * It is allowed to call ulist_add during an enumeration. Newly added items * are guaranteed to show up in the running enumeration. */ struct ulist_node *ulist_next(struct ulist *ulist, struct ulist_iterator *uiter) { struct ulist_node *node; if (list_empty(&ulist->nodes)) return NULL; if (uiter->cur_list && uiter->cur_list->next == &ulist->nodes) return NULL; if (uiter->cur_list) { uiter->cur_list = uiter->cur_list->next; } else { uiter->cur_list = ulist->nodes.next; #ifdef CONFIG_BTRFS_DEBUG uiter->i = 0; #endif } node = list_entry(uiter->cur_list, struct ulist_node, list); #ifdef CONFIG_BTRFS_DEBUG ASSERT(node->seqnum == uiter->i); ASSERT(uiter->i >= 0 && uiter->i < ulist->nnodes); uiter->i++; #endif return node; } partclone-0.2.86/src/btrfs/ulist.h000066400000000000000000000037541262102574200170300ustar00rootroot00000000000000/* * Copyright (C) 2011 STRATO AG * written by Arne Jansen * Distributed under the GNU GPL license version 2. * */ #ifndef __ULIST__ #define __ULIST__ #include "kerncompat.h" #include "list.h" #include "rbtree.h" /* * ulist is a generic data structure to hold a collection of unique u64 * values. The only operations it supports is adding to the list and * enumerating it. * It is possible to store an auxiliary value along with the key. * */ struct ulist_iterator { #ifdef CONFIG_BTRFS_DEBUG int i; #endif struct list_head *cur_list; /* hint to start search */ }; /* * element of the list */ struct ulist_node { u64 val; /* value to store */ u64 aux; /* auxiliary value saved along with the val */ #ifdef CONFIG_BTRFS_DEBUG int seqnum; /* sequence number this node is added */ #endif struct list_head list; /* used to link node */ struct rb_node rb_node; /* used to speed up search */ }; struct ulist { /* * number of elements stored in list */ unsigned long nnodes; struct list_head nodes; struct rb_root root; }; void ulist_init(struct ulist *ulist); void ulist_reinit(struct ulist *ulist); struct ulist *ulist_alloc(gfp_t gfp_mask); void ulist_free(struct ulist *ulist); int ulist_add(struct ulist *ulist, u64 val, u64 aux, gfp_t gfp_mask); int ulist_add_merge(struct ulist *ulist, u64 val, u64 aux, u64 *old_aux, gfp_t gfp_mask); /* just like ulist_add_merge() but take a pointer for the aux data */ static inline int ulist_add_merge_ptr(struct ulist *ulist, u64 val, void *aux, void **old_aux, gfp_t gfp_mask) { #if BITS_PER_LONG == 32 u64 old64 = (uintptr_t)*old_aux; int ret = ulist_add_merge(ulist, val, (uintptr_t)aux, &old64, gfp_mask); *old_aux = (void *)((uintptr_t)old64); return ret; #else return ulist_add_merge(ulist, val, (u64)aux, (u64 *)old_aux, gfp_mask); #endif } struct ulist_node *ulist_next(struct ulist *ulist, struct ulist_iterator *uiter); #define ULIST_ITER_INIT(uiter) ((uiter)->cur_list = NULL) #endif partclone-0.2.86/src/btrfs/utils-lib.c000066400000000000000000000016441262102574200175630ustar00rootroot00000000000000#define _GNU_SOURCE #include "kerncompat.h" #include #include #include #if BTRFS_FLAT_INCLUDES #else #endif /* BTRFS_FLAT_INCLUDES */ /* * This function should be only used when parsing command arg, it won't return * error to its caller and rather exit directly just like usage(). */ u64 arg_strtou64(const char *str) { u64 value; char *ptr_parse_end = NULL; value = strtoull(str, &ptr_parse_end, 0); if (ptr_parse_end && *ptr_parse_end != '\0') { fprintf(stderr, "ERROR: %s is not a valid numeric value.\n", str); exit(1); } /* * if we pass a negative number to strtoull, it will return an * unexpected number to us, so let's do the check ourselves. */ if (str[0] == '-') { fprintf(stderr, "ERROR: %s: negative value is invalid.\n", str); exit(1); } if (value == ULLONG_MAX) { fprintf(stderr, "ERROR: %s is too large.\n", str); exit(1); } return value; } partclone-0.2.86/src/btrfs/utils.c000066400000000000000000001616601262102574200170240ustar00rootroot00000000000000/* * Copyright (C) 2007 Oracle. All rights reserved. * Copyright (C) 2008 Morey Roof. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. */ #define _XOPEN_SOURCE 700 #define __USE_XOPEN2K8 #define __XOPEN2K8 /* due to an error in dirent.h, to get dirfd() */ #define _GNU_SOURCE /* O_NOATIME */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kerncompat.h" #include "radix-tree.h" #include "ctree.h" #include "disk-io.h" #include "transaction.h" #include "crc32c.h" #include "utils.h" #include "volumes.h" #include "ioctl.h" #ifndef BLKDISCARD #define BLKDISCARD _IO(0x12,119) #endif static int btrfs_scan_done = 0; static char argv0_buf[ARGV0_BUF_SIZE] = "btrfs"; void fixup_argv0(char **argv, const char *token) { int len = strlen(argv0_buf); snprintf(argv0_buf + len, sizeof(argv0_buf) - len, " %s", token); argv[0] = argv0_buf; } void set_argv0(char **argv) { strncpy(argv0_buf, argv[0], sizeof(argv0_buf)); argv0_buf[sizeof(argv0_buf) - 1] = 0; } int check_argc_exact(int nargs, int expected) { if (nargs < expected) fprintf(stderr, "%s: too few arguments\n", argv0_buf); if (nargs > expected) fprintf(stderr, "%s: too many arguments\n", argv0_buf); return nargs != expected; } int check_argc_min(int nargs, int expected) { if (nargs < expected) { fprintf(stderr, "%s: too few arguments\n", argv0_buf); return 1; } return 0; } int check_argc_max(int nargs, int expected) { if (nargs > expected) { fprintf(stderr, "%s: too many arguments\n", argv0_buf); return 1; } return 0; } /* * Discard the given range in one go */ static int discard_range(int fd, u64 start, u64 len) { u64 range[2] = { start, len }; if (ioctl(fd, BLKDISCARD, &range) < 0) return errno; return 0; } /* * Discard blocks in the given range in 1G chunks, the process is interruptible */ static int discard_blocks(int fd, u64 start, u64 len) { while (len > 0) { /* 1G granularity */ u64 chunk_size = min_t(u64, len, 1*1024*1024*1024); int ret; ret = discard_range(fd, start, chunk_size); if (ret) return ret; len -= chunk_size; start += chunk_size; } return 0; } static u64 reference_root_table[] = { [1] = BTRFS_ROOT_TREE_OBJECTID, [2] = BTRFS_EXTENT_TREE_OBJECTID, [3] = BTRFS_CHUNK_TREE_OBJECTID, [4] = BTRFS_DEV_TREE_OBJECTID, [5] = BTRFS_FS_TREE_OBJECTID, [6] = BTRFS_CSUM_TREE_OBJECTID, }; int test_uuid_unique(char *fs_uuid) { int unique = 1; blkid_dev_iterate iter = NULL; blkid_dev dev = NULL; blkid_cache cache = NULL; if (blkid_get_cache(&cache, 0) < 0) { printf("ERROR: lblkid cache get failed\n"); return 1; } blkid_probe_all(cache); iter = blkid_dev_iterate_begin(cache); blkid_dev_set_search(iter, "UUID", fs_uuid); while (blkid_dev_next(iter, &dev) == 0) { dev = blkid_verify(cache, dev); if (dev) { unique = 0; break; } } blkid_dev_iterate_end(iter); blkid_put_cache(cache); return unique; } int make_btrfs(int fd, const char *device, const char *label, char *fs_uuid, u64 blocks[7], u64 num_bytes, u32 nodesize, u32 leafsize, u32 sectorsize, u32 stripesize, u64 features) { struct btrfs_super_block super; struct extent_buffer *buf = NULL; struct btrfs_root_item root_item; struct btrfs_disk_key disk_key; struct btrfs_extent_item *extent_item; struct btrfs_inode_item *inode_item; struct btrfs_chunk *chunk; struct btrfs_dev_item *dev_item; struct btrfs_dev_extent *dev_extent; u8 chunk_tree_uuid[BTRFS_UUID_SIZE]; u8 *ptr; int i; int ret; u32 itemoff; u32 nritems = 0; u64 first_free; u64 ref_root; u32 array_size; u32 item_size; int skinny_metadata = !!(features & BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA); first_free = BTRFS_SUPER_INFO_OFFSET + sectorsize * 2 - 1; first_free &= ~((u64)sectorsize - 1); memset(&super, 0, sizeof(super)); num_bytes = (num_bytes / sectorsize) * sectorsize; if (fs_uuid) { if (uuid_parse(fs_uuid, super.fsid) != 0) { fprintf(stderr, "could not parse UUID: %s\n", fs_uuid); ret = -EINVAL; goto out; } if (!test_uuid_unique(fs_uuid)) { fprintf(stderr, "non-unique UUID: %s\n", fs_uuid); ret = -EBUSY; goto out; } } else { uuid_generate(super.fsid); } uuid_generate(super.dev_item.uuid); uuid_generate(chunk_tree_uuid); btrfs_set_super_bytenr(&super, blocks[0]); btrfs_set_super_num_devices(&super, 1); btrfs_set_super_magic(&super, BTRFS_MAGIC); btrfs_set_super_generation(&super, 1); btrfs_set_super_root(&super, blocks[1]); btrfs_set_super_chunk_root(&super, blocks[3]); btrfs_set_super_total_bytes(&super, num_bytes); btrfs_set_super_bytes_used(&super, 6 * leafsize); btrfs_set_super_sectorsize(&super, sectorsize); btrfs_set_super_leafsize(&super, leafsize); btrfs_set_super_nodesize(&super, nodesize); btrfs_set_super_stripesize(&super, stripesize); btrfs_set_super_csum_type(&super, BTRFS_CSUM_TYPE_CRC32); btrfs_set_super_chunk_root_generation(&super, 1); btrfs_set_super_cache_generation(&super, -1); btrfs_set_super_incompat_flags(&super, features); if (label) strncpy(super.label, label, BTRFS_LABEL_SIZE - 1); buf = malloc(sizeof(*buf) + max(sectorsize, leafsize)); /* create the tree of root objects */ memset(buf->data, 0, leafsize); buf->len = leafsize; btrfs_set_header_bytenr(buf, blocks[1]); btrfs_set_header_nritems(buf, 4); btrfs_set_header_generation(buf, 1); btrfs_set_header_backref_rev(buf, BTRFS_MIXED_BACKREF_REV); btrfs_set_header_owner(buf, BTRFS_ROOT_TREE_OBJECTID); write_extent_buffer(buf, super.fsid, btrfs_header_fsid(), BTRFS_FSID_SIZE); write_extent_buffer(buf, chunk_tree_uuid, btrfs_header_chunk_tree_uuid(buf), BTRFS_UUID_SIZE); /* create the items for the root tree */ memset(&root_item, 0, sizeof(root_item)); inode_item = &root_item.inode; btrfs_set_stack_inode_generation(inode_item, 1); btrfs_set_stack_inode_size(inode_item, 3); btrfs_set_stack_inode_nlink(inode_item, 1); btrfs_set_stack_inode_nbytes(inode_item, leafsize); btrfs_set_stack_inode_mode(inode_item, S_IFDIR | 0755); btrfs_set_root_refs(&root_item, 1); btrfs_set_root_used(&root_item, leafsize); btrfs_set_root_generation(&root_item, 1); memset(&disk_key, 0, sizeof(disk_key)); btrfs_set_disk_key_type(&disk_key, BTRFS_ROOT_ITEM_KEY); btrfs_set_disk_key_offset(&disk_key, 0); nritems = 0; itemoff = __BTRFS_LEAF_DATA_SIZE(leafsize) - sizeof(root_item); btrfs_set_root_bytenr(&root_item, blocks[2]); btrfs_set_disk_key_objectid(&disk_key, BTRFS_EXTENT_TREE_OBJECTID); btrfs_set_item_key(buf, &disk_key, nritems); btrfs_set_item_offset(buf, btrfs_item_nr(nritems), itemoff); btrfs_set_item_size(buf, btrfs_item_nr(nritems), sizeof(root_item)); write_extent_buffer(buf, &root_item, btrfs_item_ptr_offset(buf, nritems), sizeof(root_item)); nritems++; itemoff = itemoff - sizeof(root_item); btrfs_set_root_bytenr(&root_item, blocks[4]); btrfs_set_disk_key_objectid(&disk_key, BTRFS_DEV_TREE_OBJECTID); btrfs_set_item_key(buf, &disk_key, nritems); btrfs_set_item_offset(buf, btrfs_item_nr(nritems), itemoff); btrfs_set_item_size(buf, btrfs_item_nr(nritems), sizeof(root_item)); write_extent_buffer(buf, &root_item, btrfs_item_ptr_offset(buf, nritems), sizeof(root_item)); nritems++; itemoff = itemoff - sizeof(root_item); btrfs_set_root_bytenr(&root_item, blocks[5]); btrfs_set_disk_key_objectid(&disk_key, BTRFS_FS_TREE_OBJECTID); btrfs_set_item_key(buf, &disk_key, nritems); btrfs_set_item_offset(buf, btrfs_item_nr(nritems), itemoff); btrfs_set_item_size(buf, btrfs_item_nr(nritems), sizeof(root_item)); write_extent_buffer(buf, &root_item, btrfs_item_ptr_offset(buf, nritems), sizeof(root_item)); nritems++; itemoff = itemoff - sizeof(root_item); btrfs_set_root_bytenr(&root_item, blocks[6]); btrfs_set_disk_key_objectid(&disk_key, BTRFS_CSUM_TREE_OBJECTID); btrfs_set_item_key(buf, &disk_key, nritems); btrfs_set_item_offset(buf, btrfs_item_nr(nritems), itemoff); btrfs_set_item_size(buf, btrfs_item_nr(nritems), sizeof(root_item)); write_extent_buffer(buf, &root_item, btrfs_item_ptr_offset(buf, nritems), sizeof(root_item)); nritems++; csum_tree_block_size(buf, BTRFS_CRC32_SIZE, 0); ret = pwrite(fd, buf->data, leafsize, blocks[1]); if (ret != leafsize) { ret = (ret < 0 ? -errno : -EIO); goto out; } /* create the items for the extent tree */ memset(buf->data+sizeof(struct btrfs_header), 0, leafsize-sizeof(struct btrfs_header)); nritems = 0; itemoff = __BTRFS_LEAF_DATA_SIZE(leafsize); for (i = 1; i < 7; i++) { item_size = sizeof(struct btrfs_extent_item); if (!skinny_metadata) item_size += sizeof(struct btrfs_tree_block_info); BUG_ON(blocks[i] < first_free); BUG_ON(blocks[i] < blocks[i - 1]); /* create extent item */ itemoff -= item_size; btrfs_set_disk_key_objectid(&disk_key, blocks[i]); if (skinny_metadata) { btrfs_set_disk_key_type(&disk_key, BTRFS_METADATA_ITEM_KEY); btrfs_set_disk_key_offset(&disk_key, 0); } else { btrfs_set_disk_key_type(&disk_key, BTRFS_EXTENT_ITEM_KEY); btrfs_set_disk_key_offset(&disk_key, leafsize); } btrfs_set_item_key(buf, &disk_key, nritems); btrfs_set_item_offset(buf, btrfs_item_nr(nritems), itemoff); btrfs_set_item_size(buf, btrfs_item_nr(nritems), item_size); extent_item = btrfs_item_ptr(buf, nritems, struct btrfs_extent_item); btrfs_set_extent_refs(buf, extent_item, 1); btrfs_set_extent_generation(buf, extent_item, 1); btrfs_set_extent_flags(buf, extent_item, BTRFS_EXTENT_FLAG_TREE_BLOCK); nritems++; /* create extent ref */ ref_root = reference_root_table[i]; btrfs_set_disk_key_objectid(&disk_key, blocks[i]); btrfs_set_disk_key_offset(&disk_key, ref_root); btrfs_set_disk_key_type(&disk_key, BTRFS_TREE_BLOCK_REF_KEY); btrfs_set_item_key(buf, &disk_key, nritems); btrfs_set_item_offset(buf, btrfs_item_nr(nritems), itemoff); btrfs_set_item_size(buf, btrfs_item_nr(nritems), 0); nritems++; } btrfs_set_header_bytenr(buf, blocks[2]); btrfs_set_header_owner(buf, BTRFS_EXTENT_TREE_OBJECTID); btrfs_set_header_nritems(buf, nritems); csum_tree_block_size(buf, BTRFS_CRC32_SIZE, 0); ret = pwrite(fd, buf->data, leafsize, blocks[2]); if (ret != leafsize) { ret = (ret < 0 ? -errno : -EIO); goto out; } /* create the chunk tree */ memset(buf->data+sizeof(struct btrfs_header), 0, leafsize-sizeof(struct btrfs_header)); nritems = 0; item_size = sizeof(*dev_item); itemoff = __BTRFS_LEAF_DATA_SIZE(leafsize) - item_size; /* first device 1 (there is no device 0) */ btrfs_set_disk_key_objectid(&disk_key, BTRFS_DEV_ITEMS_OBJECTID); btrfs_set_disk_key_offset(&disk_key, 1); btrfs_set_disk_key_type(&disk_key, BTRFS_DEV_ITEM_KEY); btrfs_set_item_key(buf, &disk_key, nritems); btrfs_set_item_offset(buf, btrfs_item_nr(nritems), itemoff); btrfs_set_item_size(buf, btrfs_item_nr(nritems), item_size); dev_item = btrfs_item_ptr(buf, nritems, struct btrfs_dev_item); btrfs_set_device_id(buf, dev_item, 1); btrfs_set_device_generation(buf, dev_item, 0); btrfs_set_device_total_bytes(buf, dev_item, num_bytes); btrfs_set_device_bytes_used(buf, dev_item, BTRFS_MKFS_SYSTEM_GROUP_SIZE); btrfs_set_device_io_align(buf, dev_item, sectorsize); btrfs_set_device_io_width(buf, dev_item, sectorsize); btrfs_set_device_sector_size(buf, dev_item, sectorsize); btrfs_set_device_type(buf, dev_item, 0); write_extent_buffer(buf, super.dev_item.uuid, (unsigned long)btrfs_device_uuid(dev_item), BTRFS_UUID_SIZE); write_extent_buffer(buf, super.fsid, (unsigned long)btrfs_device_fsid(dev_item), BTRFS_UUID_SIZE); read_extent_buffer(buf, &super.dev_item, (unsigned long)dev_item, sizeof(*dev_item)); nritems++; item_size = btrfs_chunk_item_size(1); itemoff = itemoff - item_size; /* then we have chunk 0 */ btrfs_set_disk_key_objectid(&disk_key, BTRFS_FIRST_CHUNK_TREE_OBJECTID); btrfs_set_disk_key_offset(&disk_key, 0); btrfs_set_disk_key_type(&disk_key, BTRFS_CHUNK_ITEM_KEY); btrfs_set_item_key(buf, &disk_key, nritems); btrfs_set_item_offset(buf, btrfs_item_nr(nritems), itemoff); btrfs_set_item_size(buf, btrfs_item_nr(nritems), item_size); chunk = btrfs_item_ptr(buf, nritems, struct btrfs_chunk); btrfs_set_chunk_length(buf, chunk, BTRFS_MKFS_SYSTEM_GROUP_SIZE); btrfs_set_chunk_owner(buf, chunk, BTRFS_EXTENT_TREE_OBJECTID); btrfs_set_chunk_stripe_len(buf, chunk, 64 * 1024); btrfs_set_chunk_type(buf, chunk, BTRFS_BLOCK_GROUP_SYSTEM); btrfs_set_chunk_io_align(buf, chunk, sectorsize); btrfs_set_chunk_io_width(buf, chunk, sectorsize); btrfs_set_chunk_sector_size(buf, chunk, sectorsize); btrfs_set_chunk_num_stripes(buf, chunk, 1); btrfs_set_stripe_devid_nr(buf, chunk, 0, 1); btrfs_set_stripe_offset_nr(buf, chunk, 0, 0); nritems++; write_extent_buffer(buf, super.dev_item.uuid, (unsigned long)btrfs_stripe_dev_uuid(&chunk->stripe), BTRFS_UUID_SIZE); /* copy the key for the chunk to the system array */ ptr = super.sys_chunk_array; array_size = sizeof(disk_key); memcpy(ptr, &disk_key, sizeof(disk_key)); ptr += sizeof(disk_key); /* copy the chunk to the system array */ read_extent_buffer(buf, ptr, (unsigned long)chunk, item_size); array_size += item_size; ptr += item_size; btrfs_set_super_sys_array_size(&super, array_size); btrfs_set_header_bytenr(buf, blocks[3]); btrfs_set_header_owner(buf, BTRFS_CHUNK_TREE_OBJECTID); btrfs_set_header_nritems(buf, nritems); csum_tree_block_size(buf, BTRFS_CRC32_SIZE, 0); ret = pwrite(fd, buf->data, leafsize, blocks[3]); if (ret != leafsize) { ret = (ret < 0 ? -errno : -EIO); goto out; } /* create the device tree */ memset(buf->data+sizeof(struct btrfs_header), 0, leafsize-sizeof(struct btrfs_header)); nritems = 0; itemoff = __BTRFS_LEAF_DATA_SIZE(leafsize) - sizeof(struct btrfs_dev_extent); btrfs_set_disk_key_objectid(&disk_key, 1); btrfs_set_disk_key_offset(&disk_key, 0); btrfs_set_disk_key_type(&disk_key, BTRFS_DEV_EXTENT_KEY); btrfs_set_item_key(buf, &disk_key, nritems); btrfs_set_item_offset(buf, btrfs_item_nr(nritems), itemoff); btrfs_set_item_size(buf, btrfs_item_nr(nritems), sizeof(struct btrfs_dev_extent)); dev_extent = btrfs_item_ptr(buf, nritems, struct btrfs_dev_extent); btrfs_set_dev_extent_chunk_tree(buf, dev_extent, BTRFS_CHUNK_TREE_OBJECTID); btrfs_set_dev_extent_chunk_objectid(buf, dev_extent, BTRFS_FIRST_CHUNK_TREE_OBJECTID); btrfs_set_dev_extent_chunk_offset(buf, dev_extent, 0); write_extent_buffer(buf, chunk_tree_uuid, (unsigned long)btrfs_dev_extent_chunk_tree_uuid(dev_extent), BTRFS_UUID_SIZE); btrfs_set_dev_extent_length(buf, dev_extent, BTRFS_MKFS_SYSTEM_GROUP_SIZE); nritems++; btrfs_set_header_bytenr(buf, blocks[4]); btrfs_set_header_owner(buf, BTRFS_DEV_TREE_OBJECTID); btrfs_set_header_nritems(buf, nritems); csum_tree_block_size(buf, BTRFS_CRC32_SIZE, 0); ret = pwrite(fd, buf->data, leafsize, blocks[4]); if (ret != leafsize) { ret = (ret < 0 ? -errno : -EIO); goto out; } /* create the FS root */ memset(buf->data+sizeof(struct btrfs_header), 0, leafsize-sizeof(struct btrfs_header)); btrfs_set_header_bytenr(buf, blocks[5]); btrfs_set_header_owner(buf, BTRFS_FS_TREE_OBJECTID); btrfs_set_header_nritems(buf, 0); csum_tree_block_size(buf, BTRFS_CRC32_SIZE, 0); ret = pwrite(fd, buf->data, leafsize, blocks[5]); if (ret != leafsize) { ret = (ret < 0 ? -errno : -EIO); goto out; } /* finally create the csum root */ memset(buf->data+sizeof(struct btrfs_header), 0, leafsize-sizeof(struct btrfs_header)); btrfs_set_header_bytenr(buf, blocks[6]); btrfs_set_header_owner(buf, BTRFS_CSUM_TREE_OBJECTID); btrfs_set_header_nritems(buf, 0); csum_tree_block_size(buf, BTRFS_CRC32_SIZE, 0); ret = pwrite(fd, buf->data, leafsize, blocks[6]); if (ret != leafsize) { ret = (ret < 0 ? -errno : -EIO); goto out; } /* and write out the super block */ BUG_ON(sizeof(super) > sectorsize); memset(buf->data, 0, sectorsize); memcpy(buf->data, &super, sizeof(super)); buf->len = sectorsize; csum_tree_block_size(buf, BTRFS_CRC32_SIZE, 0); ret = pwrite(fd, buf->data, sectorsize, blocks[0]); if (ret != sectorsize) { ret = (ret < 0 ? -errno : -EIO); goto out; } ret = 0; out: free(buf); return ret; } u64 btrfs_device_size(int fd, struct stat *st) { u64 size; if (S_ISREG(st->st_mode)) { return st->st_size; } if (!S_ISBLK(st->st_mode)) { return 0; } if (ioctl(fd, BLKGETSIZE64, &size) >= 0) { return size; } return 0; } static int zero_blocks(int fd, off_t start, size_t len) { char *buf = malloc(len); int ret = 0; ssize_t written; if (!buf) return -ENOMEM; memset(buf, 0, len); written = pwrite(fd, buf, len, start); if (written != len) ret = -EIO; free(buf); return ret; } #define ZERO_DEV_BYTES (2 * 1024 * 1024) /* don't write outside the device by clamping the region to the device size */ static int zero_dev_clamped(int fd, off_t start, ssize_t len, u64 dev_size) { off_t end = max(start, start + len); #ifdef __sparc__ /* and don't overwrite the disk labels on sparc */ start = max(start, 1024); end = max(end, 1024); #endif start = min_t(u64, start, dev_size); end = min_t(u64, end, dev_size); return zero_blocks(fd, start, end - start); } int btrfs_add_to_fsid(struct btrfs_trans_handle *trans, struct btrfs_root *root, int fd, char *path, u64 block_count, u32 io_width, u32 io_align, u32 sectorsize) { struct btrfs_super_block *disk_super; struct btrfs_super_block *super = root->fs_info->super_copy; struct btrfs_device *device; struct btrfs_dev_item *dev_item; char *buf; u64 total_bytes; u64 num_devs; int ret; device = kzalloc(sizeof(*device), GFP_NOFS); if (!device) return -ENOMEM; buf = kmalloc(sectorsize, GFP_NOFS); if (!buf) { kfree(device); return -ENOMEM; } BUG_ON(sizeof(*disk_super) > sectorsize); memset(buf, 0, sectorsize); disk_super = (struct btrfs_super_block *)buf; dev_item = &disk_super->dev_item; uuid_generate(device->uuid); device->devid = 0; device->type = 0; device->io_width = io_width; device->io_align = io_align; device->sector_size = sectorsize; device->fd = fd; device->writeable = 1; device->total_bytes = block_count; device->bytes_used = 0; device->total_ios = 0; device->dev_root = root->fs_info->dev_root; ret = btrfs_add_device(trans, root, device); BUG_ON(ret); total_bytes = btrfs_super_total_bytes(super) + block_count; btrfs_set_super_total_bytes(super, total_bytes); num_devs = btrfs_super_num_devices(super) + 1; btrfs_set_super_num_devices(super, num_devs); memcpy(disk_super, super, sizeof(*disk_super)); printf("adding device %s id %llu\n", path, (unsigned long long)device->devid); btrfs_set_super_bytenr(disk_super, BTRFS_SUPER_INFO_OFFSET); btrfs_set_stack_device_id(dev_item, device->devid); btrfs_set_stack_device_type(dev_item, device->type); btrfs_set_stack_device_io_align(dev_item, device->io_align); btrfs_set_stack_device_io_width(dev_item, device->io_width); btrfs_set_stack_device_sector_size(dev_item, device->sector_size); btrfs_set_stack_device_total_bytes(dev_item, device->total_bytes); btrfs_set_stack_device_bytes_used(dev_item, device->bytes_used); memcpy(&dev_item->uuid, device->uuid, BTRFS_UUID_SIZE); ret = pwrite(fd, buf, sectorsize, BTRFS_SUPER_INFO_OFFSET); BUG_ON(ret != sectorsize); kfree(buf); list_add(&device->dev_list, &root->fs_info->fs_devices->devices); device->fs_devices = root->fs_info->fs_devices; return 0; } static void btrfs_wipe_existing_sb(int fd) { const char *off = NULL; size_t len = 0; loff_t offset; char buf[BUFSIZ]; int rc = 0; blkid_probe pr = NULL; pr = blkid_new_probe(); if (!pr) return; if (blkid_probe_set_device(pr, fd, 0, 0)) goto out; rc = blkid_probe_lookup_value(pr, "SBMAGIC_OFFSET", &off, NULL); if (!rc) rc = blkid_probe_lookup_value(pr, "SBMAGIC", NULL, &len); if (rc || len == 0 || off == NULL) goto out; offset = strtoll(off, NULL, 10); if (len > sizeof(buf)) len = sizeof(buf); memset(buf, 0, len); rc = pwrite(fd, buf, len, offset); fsync(fd); out: blkid_free_probe(pr); return; } int btrfs_prepare_device(int fd, char *file, int zero_end, u64 *block_count_ret, u64 max_block_count, int *mixed, int discard) { u64 block_count; struct stat st; int i, ret; ret = fstat(fd, &st); if (ret < 0) { fprintf(stderr, "unable to stat %s\n", file); return 1; } block_count = btrfs_device_size(fd, &st); if (block_count == 0) { fprintf(stderr, "unable to find %s size\n", file); return 1; } if (max_block_count) block_count = min(block_count, max_block_count); if (block_count < BTRFS_MKFS_SMALL_VOLUME_SIZE && !(*mixed)) *mixed = 1; if (discard) { /* * We intentionally ignore errors from the discard ioctl. It * is not necessary for the mkfs functionality but just an * optimization. */ if (discard_range(fd, 0, 0) == 0) { fprintf(stderr, "Performing full device TRIM (%s) ...\n", pretty_size(block_count)); discard_blocks(fd, 0, block_count); } } ret = zero_dev_clamped(fd, 0, ZERO_DEV_BYTES, block_count); for (i = 0 ; !ret && i < BTRFS_SUPER_MIRROR_MAX; i++) ret = zero_dev_clamped(fd, btrfs_sb_offset(i), BTRFS_SUPER_INFO_SIZE, block_count); if (!ret && zero_end) ret = zero_dev_clamped(fd, block_count - ZERO_DEV_BYTES, ZERO_DEV_BYTES, block_count); if (ret < 0) { fprintf(stderr, "ERROR: failed to zero device '%s' - %s\n", file, strerror(-ret)); return 1; } btrfs_wipe_existing_sb(fd); *block_count_ret = block_count; return 0; } int btrfs_make_root_dir(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 objectid) { int ret; struct btrfs_inode_item inode_item; time_t now = time(NULL); memset(&inode_item, 0, sizeof(inode_item)); btrfs_set_stack_inode_generation(&inode_item, trans->transid); btrfs_set_stack_inode_size(&inode_item, 0); btrfs_set_stack_inode_nlink(&inode_item, 1); btrfs_set_stack_inode_nbytes(&inode_item, root->leafsize); btrfs_set_stack_inode_mode(&inode_item, S_IFDIR | 0755); btrfs_set_stack_timespec_sec(&inode_item.atime, now); btrfs_set_stack_timespec_nsec(&inode_item.atime, 0); btrfs_set_stack_timespec_sec(&inode_item.ctime, now); btrfs_set_stack_timespec_nsec(&inode_item.ctime, 0); btrfs_set_stack_timespec_sec(&inode_item.mtime, now); btrfs_set_stack_timespec_nsec(&inode_item.mtime, 0); btrfs_set_stack_timespec_sec(&inode_item.otime, 0); btrfs_set_stack_timespec_nsec(&inode_item.otime, 0); if (root->fs_info->tree_root == root) btrfs_set_super_root_dir(root->fs_info->super_copy, objectid); ret = btrfs_insert_inode(trans, root, objectid, &inode_item); if (ret) goto error; ret = btrfs_insert_inode_ref(trans, root, "..", 2, objectid, objectid, 0); if (ret) goto error; btrfs_set_root_dirid(&root->root_item, objectid); ret = 0; error: return ret; } /* * checks if a path is a block device node * Returns negative errno on failure, otherwise * returns 1 for blockdev, 0 for not-blockdev */ int is_block_device(const char *path) { struct stat statbuf; if (stat(path, &statbuf) < 0) return -errno; return S_ISBLK(statbuf.st_mode); } /* * check if given path is a mount point * return 1 if yes. 0 if no. -1 for error */ int is_mount_point(const char *path) { FILE *f; struct mntent *mnt; int ret = 0; f = setmntent("/proc/self/mounts", "r"); if (f == NULL) return -1; while ((mnt = getmntent(f)) != NULL) { if (strcmp(mnt->mnt_dir, path)) continue; ret = 1; break; } endmntent(f); return ret; } /* * Find the mount point for a mounted device. * On success, returns 0 with mountpoint in *mp. * On failure, returns -errno (not mounted yields -EINVAL) * Is noisy on failures, expects to be given a mounted device. */ int get_btrfs_mount(const char *dev, char *mp, size_t mp_size) { int ret; int fd = -1; ret = is_block_device(dev); if (ret <= 0) { if (!ret) { fprintf(stderr, "%s is not a block device\n", dev); ret = -EINVAL; } else { fprintf(stderr, "Could not check %s: %s\n", dev, strerror(-ret)); } goto out; } fd = open(dev, O_RDONLY); if (fd < 0) { ret = -errno; fprintf(stderr, "Could not open %s: %s\n", dev, strerror(errno)); goto out; } ret = check_mounted_where(fd, dev, mp, mp_size, NULL); if (!ret) { ret = -EINVAL; } else { /* mounted, all good */ ret = 0; } out: if (fd != -1) close(fd); return ret; } /* * Given a pathname, return a filehandle to: * the original pathname or, * if the pathname is a mounted btrfs device, to its mountpoint. * * On error, return -1, errno should be set. */ int open_path_or_dev_mnt(const char *path, DIR **dirstream) { char mp[BTRFS_PATH_NAME_MAX + 1]; int fdmnt; if (is_block_device(path)) { int ret; ret = get_btrfs_mount(path, mp, sizeof(mp)); if (ret < 0) { /* not a mounted btrfs dev */ errno = EINVAL; return -1; } fdmnt = open_file_or_dir(mp, dirstream); } else { fdmnt = open_file_or_dir(path, dirstream); } return fdmnt; } /* checks if a device is a loop device */ static int is_loop_device (const char* device) { struct stat statbuf; if(stat(device, &statbuf) < 0) return -errno; return (S_ISBLK(statbuf.st_mode) && MAJOR(statbuf.st_rdev) == LOOP_MAJOR); } /* Takes a loop device path (e.g. /dev/loop0) and returns * the associated file (e.g. /images/my_btrfs.img) */ static int resolve_loop_device(const char* loop_dev, char* loop_file, int max_len) { int ret; FILE *f; char fmt[20]; char p[PATH_MAX]; char real_loop_dev[PATH_MAX]; if (!realpath(loop_dev, real_loop_dev)) return -errno; snprintf(p, PATH_MAX, "/sys/block/%s/loop/backing_file", strrchr(real_loop_dev, '/')); if (!(f = fopen(p, "r"))) return -errno; snprintf(fmt, 20, "%%%i[^\n]", max_len-1); ret = fscanf(f, fmt, loop_file); fclose(f); if (ret == EOF) return -errno; return 0; } /* Checks whether a and b are identical or device * files associated with the same block device */ static int is_same_blk_file(const char* a, const char* b) { struct stat st_buf_a, st_buf_b; char real_a[PATH_MAX]; char real_b[PATH_MAX]; if(!realpath(a, real_a)) strcpy(real_a, a); if (!realpath(b, real_b)) strcpy(real_b, b); /* Identical path? */ if(strcmp(real_a, real_b) == 0) return 1; if(stat(a, &st_buf_a) < 0 || stat(b, &st_buf_b) < 0) { if (errno == ENOENT) return 0; return -errno; } /* Same blockdevice? */ if(S_ISBLK(st_buf_a.st_mode) && S_ISBLK(st_buf_b.st_mode) && st_buf_a.st_rdev == st_buf_b.st_rdev) { return 1; } /* Hardlink? */ if (st_buf_a.st_dev == st_buf_b.st_dev && st_buf_a.st_ino == st_buf_b.st_ino) { return 1; } return 0; } /* checks if a and b are identical or device * files associated with the same block device or * if one file is a loop device that uses the other * file. */ static int is_same_loop_file(const char* a, const char* b) { char res_a[PATH_MAX]; char res_b[PATH_MAX]; const char* final_a = NULL; const char* final_b = NULL; int ret; /* Resolve a if it is a loop device */ if((ret = is_loop_device(a)) < 0) { if (ret == -ENOENT) return 0; return ret; } else if (ret) { ret = resolve_loop_device(a, res_a, sizeof(res_a)); if (ret < 0) { if (errno != EPERM) return ret; } else { final_a = res_a; } } else { final_a = a; } /* Resolve b if it is a loop device */ if ((ret = is_loop_device(b)) < 0) { if (ret == -ENOENT) return 0; return ret; } else if (ret) { ret = resolve_loop_device(b, res_b, sizeof(res_b)); if (ret < 0) { if (errno != EPERM) return ret; } else { final_b = res_b; } } else { final_b = b; } return is_same_blk_file(final_a, final_b); } /* Checks if a file exists and is a block or regular file*/ static int is_existing_blk_or_reg_file(const char* filename) { struct stat st_buf; if(stat(filename, &st_buf) < 0) { if(errno == ENOENT) return 0; else return -errno; } return (S_ISBLK(st_buf.st_mode) || S_ISREG(st_buf.st_mode)); } /* Checks if a file is used (directly or indirectly via a loop device) * by a device in fs_devices */ static int blk_file_in_dev_list(struct btrfs_fs_devices* fs_devices, const char* file) { int ret; struct list_head *head; struct list_head *cur; struct btrfs_device *device; head = &fs_devices->devices; list_for_each(cur, head) { device = list_entry(cur, struct btrfs_device, dev_list); if((ret = is_same_loop_file(device->name, file))) return ret; } return 0; } /* * Resolve a pathname to a device mapper node to /dev/mapper/ * Returns NULL on invalid input or malloc failure; Other failures * will be handled by the caller using the input pathame. */ char *canonicalize_dm_name(const char *ptname) { FILE *f; size_t sz; char path[PATH_MAX], name[PATH_MAX], *res = NULL; if (!ptname || !*ptname) return NULL; snprintf(path, sizeof(path), "/sys/block/%s/dm/name", ptname); if (!(f = fopen(path, "r"))) return NULL; /* read \n from sysfs */ if (fgets(name, sizeof(name), f) && (sz = strlen(name)) > 1) { name[sz - 1] = '\0'; snprintf(path, sizeof(path), "/dev/mapper/%s", name); if (access(path, F_OK) == 0) res = strdup(path); } fclose(f); return res; } /* * Resolve a pathname to a canonical device node, e.g. /dev/sda1 or * to a device mapper pathname. * Returns NULL on invalid input or malloc failure; Other failures * will be handled by the caller using the input pathame. */ char *canonicalize_path(const char *path) { char *canonical, *p; if (!path || !*path) return NULL; canonical = realpath(path, NULL); if (!canonical) return strdup(path); p = strrchr(canonical, '/'); if (p && strncmp(p, "/dm-", 4) == 0 && isdigit(*(p + 4))) { char *dm = canonicalize_dm_name(p + 1); if (dm) { free(canonical); return dm; } } return canonical; } /* * returns 1 if the device was mounted, < 0 on error or 0 if everything * is safe to continue. */ int check_mounted(const char* file) { int fd; int ret; fd = open(file, O_RDONLY); if (fd < 0) { fprintf (stderr, "check_mounted(): Could not open %s\n", file); return -errno; } ret = check_mounted_where(fd, file, NULL, 0, NULL); close(fd); return ret; } int check_mounted_where(int fd, const char *file, char *where, int size, struct btrfs_fs_devices **fs_dev_ret) { int ret; u64 total_devs = 1; int is_btrfs; struct btrfs_fs_devices *fs_devices_mnt = NULL; FILE *f; struct mntent *mnt; /* scan the initial device */ ret = btrfs_scan_one_device(fd, file, &fs_devices_mnt, &total_devs, BTRFS_SUPER_INFO_OFFSET, 0); is_btrfs = (ret >= 0); /* scan other devices */ if (is_btrfs && total_devs > 1) { ret = btrfs_scan_lblkid(); if (ret) return ret; } /* iterate over the list of currently mountes filesystems */ if ((f = setmntent ("/proc/self/mounts", "r")) == NULL) return -errno; while ((mnt = getmntent (f)) != NULL) { if(is_btrfs) { if(strcmp(mnt->mnt_type, "btrfs") != 0) continue; ret = blk_file_in_dev_list(fs_devices_mnt, mnt->mnt_fsname); } else { /* ignore entries in the mount table that are not associated with a file*/ if((ret = is_existing_blk_or_reg_file(mnt->mnt_fsname)) < 0) goto out_mntloop_err; else if(!ret) continue; ret = is_same_loop_file(file, mnt->mnt_fsname); } if(ret < 0) goto out_mntloop_err; else if(ret) break; } /* Did we find an entry in mnt table? */ if (mnt && size && where) { strncpy(where, mnt->mnt_dir, size); where[size-1] = 0; } if (fs_dev_ret) *fs_dev_ret = fs_devices_mnt; ret = (mnt != NULL); out_mntloop_err: endmntent (f); return ret; } struct pending_dir { struct list_head list; char name[PATH_MAX]; }; int btrfs_register_one_device(const char *fname) { struct btrfs_ioctl_vol_args args; int fd; int ret; int e; fd = open("/dev/btrfs-control", O_RDWR); if (fd < 0) { fprintf(stderr, "failed to open /dev/btrfs-control " "skipping device registration: %s\n", strerror(errno)); return -errno; } strncpy(args.name, fname, BTRFS_PATH_NAME_MAX); args.name[BTRFS_PATH_NAME_MAX-1] = 0; ret = ioctl(fd, BTRFS_IOC_SCAN_DEV, &args); e = errno; if (ret < 0) { fprintf(stderr, "ERROR: device scan failed '%s' - %s\n", fname, strerror(e)); ret = -e; } close(fd); return ret; } /* * Register all devices in the fs_uuid list created in the user * space. Ensure btrfs_scan_lblkid() is called before this func. */ int btrfs_register_all_devices(void) { int err; struct btrfs_fs_devices *fs_devices; struct btrfs_device *device; struct list_head *all_uuids; all_uuids = btrfs_scanned_uuids(); list_for_each_entry(fs_devices, all_uuids, list) { list_for_each_entry(device, &fs_devices->devices, dev_list) { if (strlen(device->name) != 0) { err = btrfs_register_one_device(device->name); if (err < 0) return err; if (err > 0) return -err; } } } return 0; } int btrfs_device_already_in_root(struct btrfs_root *root, int fd, int super_offset) { struct btrfs_super_block *disk_super; char *buf; int ret = 0; buf = malloc(BTRFS_SUPER_INFO_SIZE); if (!buf) { ret = -ENOMEM; goto out; } ret = pread(fd, buf, BTRFS_SUPER_INFO_SIZE, super_offset); if (ret != BTRFS_SUPER_INFO_SIZE) goto brelse; ret = 0; disk_super = (struct btrfs_super_block *)buf; if (btrfs_super_magic(disk_super) != BTRFS_MAGIC) goto brelse; if (!memcmp(disk_super->fsid, root->fs_info->super_copy->fsid, BTRFS_FSID_SIZE)) ret = 1; brelse: free(buf); out: return ret; } static const char* unit_suffix_binary[] = { "B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB"}; static const char* unit_suffix_decimal[] = { "B", "kB", "MB", "GB", "TB", "PB", "EB"}; int pretty_size_snprintf(u64 size, char *str, size_t str_size, unsigned unit_mode) { int num_divs; float fraction; u64 base = 0; int mult = 0; const char** suffix = NULL; u64 last_size; if (str_size == 0) return 0; if ((unit_mode & ~UNITS_MODE_MASK) == UNITS_RAW) { snprintf(str, str_size, "%llu", size); return 0; } if ((unit_mode & ~UNITS_MODE_MASK) == UNITS_BINARY) { base = 1024; mult = 1024; suffix = unit_suffix_binary; } else if ((unit_mode & ~UNITS_MODE_MASK) == UNITS_DECIMAL) { base = 1000; mult = 1000; suffix = unit_suffix_decimal; } /* Unknown mode */ if (!base) { fprintf(stderr, "INTERNAL ERROR: unknown unit base, mode %d\n", unit_mode); assert(0); return -1; } num_divs = 0; last_size = size; switch (unit_mode & UNITS_MODE_MASK) { case UNITS_TBYTES: base *= mult; num_divs++; case UNITS_GBYTES: base *= mult; num_divs++; case UNITS_MBYTES: base *= mult; num_divs++; case UNITS_KBYTES: num_divs++; break; case UNITS_BYTES: base = 1; num_divs = 0; break; default: while (size >= mult) { last_size = size; size /= mult; num_divs++; } } if (num_divs >= ARRAY_SIZE(unit_suffix_binary)) { str[0] = '\0'; printf("INTERNAL ERROR: unsupported unit suffix, index %d\n", num_divs); assert(0); return -1; } fraction = (float)last_size / base; return snprintf(str, str_size, "%.2f%s", fraction, suffix[num_divs]); } /* * __strncpy__null - strncpy with null termination * @dest: the target array * @src: the source string * @n: maximum bytes to copy (size of *dest) * * Like strncpy, but ensures destination is null-terminated. * * Copies the string pointed to by src, including the terminating null * byte ('\0'), to the buffer pointed to by dest, up to a maximum * of n bytes. Then ensure that dest is null-terminated. */ char *__strncpy__null(char *dest, const char *src, size_t n) { strncpy(dest, src, n); if (n > 0) dest[n - 1] = '\0'; return dest; } /* * Checks to make sure that the label matches our requirements. * Returns: 0 if everything is safe and usable -1 if the label is too long */ static int check_label(const char *input) { int len = strlen(input); if (len > BTRFS_LABEL_SIZE - 1) { fprintf(stderr, "ERROR: Label %s is too long (max %d)\n", input, BTRFS_LABEL_SIZE - 1); return -1; } return 0; } static int set_label_unmounted(const char *dev, const char *label) { struct btrfs_trans_handle *trans; struct btrfs_root *root; int ret; ret = check_mounted(dev); if (ret < 0) { fprintf(stderr, "FATAL: error checking %s mount status\n", dev); return -1; } if (ret > 0) { fprintf(stderr, "ERROR: dev %s is mounted, use mount point\n", dev); return -1; } /* Open the super_block at the default location * and as read-write. */ root = open_ctree(dev, 0, OPEN_CTREE_WRITES); if (!root) /* errors are printed by open_ctree() */ return -1; trans = btrfs_start_transaction(root, 1); snprintf(root->fs_info->super_copy->label, BTRFS_LABEL_SIZE, "%s", label); btrfs_commit_transaction(trans, root); /* Now we close it since we are done. */ close_ctree(root); return 0; } static int set_label_mounted(const char *mount_path, const char *label) { int fd; fd = open(mount_path, O_RDONLY | O_NOATIME); if (fd < 0) { fprintf(stderr, "ERROR: unable to access '%s'\n", mount_path); return -1; } if (ioctl(fd, BTRFS_IOC_SET_FSLABEL, label) < 0) { fprintf(stderr, "ERROR: unable to set label %s\n", strerror(errno)); close(fd); return -1; } close(fd); return 0; } static int get_label_unmounted(const char *dev, char *label) { struct btrfs_root *root; int ret; ret = check_mounted(dev); if (ret < 0) { fprintf(stderr, "FATAL: error checking %s mount status\n", dev); return -1; } if (ret > 0) { fprintf(stderr, "ERROR: dev %s is mounted, use mount point\n", dev); return -1; } /* Open the super_block at the default location * and as read-only. */ root = open_ctree(dev, 0, 0); if(!root) return -1; memcpy(label, root->fs_info->super_copy->label, BTRFS_LABEL_SIZE); /* Now we close it since we are done. */ close_ctree(root); return 0; } /* * If a partition is mounted, try to get the filesystem label via its * mounted path rather than device. Return the corresponding error * the user specified the device path. */ int get_label_mounted(const char *mount_path, char *labelp) { char label[BTRFS_LABEL_SIZE]; int fd; fd = open(mount_path, O_RDONLY | O_NOATIME); if (fd < 0) { fprintf(stderr, "ERROR: unable to access '%s'\n", mount_path); return -1; } memset(label, '\0', sizeof(label)); if (ioctl(fd, BTRFS_IOC_GET_FSLABEL, label) < 0) { fprintf(stderr, "ERROR: unable get label %s\n", strerror(errno)); close(fd); return -1; } strncpy(labelp, label, sizeof(label)); close(fd); return 0; } int get_label(const char *btrfs_dev, char *label) { int ret; ret = is_existing_blk_or_reg_file(btrfs_dev); if (!ret) ret = get_label_mounted(btrfs_dev, label); else if (ret > 0) ret = get_label_unmounted(btrfs_dev, label); return ret; } int set_label(const char *btrfs_dev, const char *label) { int ret; if (check_label(label)) return -1; ret = is_existing_blk_or_reg_file(btrfs_dev); if (!ret) ret = set_label_mounted(btrfs_dev, label); else if (ret > 0) ret = set_label_unmounted(btrfs_dev, label); return ret; } int btrfs_scan_block_devices(int run_ioctl) { struct stat st; int ret; int fd; struct btrfs_fs_devices *tmp_devices; u64 num_devices; FILE *proc_partitions; int i; char buf[1024]; char fullpath[110]; int scans = 0; int special; scan_again: proc_partitions = fopen("/proc/partitions","r"); if (!proc_partitions) { fprintf(stderr, "Unable to open '/proc/partitions' for scanning\n"); return -ENOENT; } /* skip the header */ for (i = 0; i < 2; i++) if (!fgets(buf, 1023, proc_partitions)) { fprintf(stderr, "Unable to read '/proc/partitions' for scanning\n"); fclose(proc_partitions); return -ENOENT; } strcpy(fullpath,"/dev/"); while(fgets(buf, 1023, proc_partitions)) { ret = sscanf(buf," %*d %*d %*d %99s", fullpath + 5); if (ret != 1) { fprintf(stderr, "failed to scan device name from /proc/partitions\n"); break; } /* * multipath and MD devices may register as a btrfs filesystem * both through the original block device and through * the special (/dev/mapper or /dev/mdX) entry. * This scans the special entries last */ special = strncmp(fullpath, "/dev/dm-", strlen("/dev/dm-")) == 0; if (!special) special = strncmp(fullpath, "/dev/md", strlen("/dev/md")) == 0; if (scans == 0 && special) continue; if (scans > 0 && !special) continue; ret = lstat(fullpath, &st); if (ret < 0) { fprintf(stderr, "failed to stat %s\n", fullpath); continue; } if (!S_ISBLK(st.st_mode)) { continue; } fd = open(fullpath, O_RDONLY); if (fd < 0) { if (errno != ENOMEDIUM) fprintf(stderr, "failed to open %s: %s\n", fullpath, strerror(errno)); continue; } ret = btrfs_scan_one_device(fd, fullpath, &tmp_devices, &num_devices, BTRFS_SUPER_INFO_OFFSET, 0); if (ret == 0 && run_ioctl > 0) { btrfs_register_one_device(fullpath); } close(fd); } fclose(proc_partitions); if (scans == 0) { scans++; goto scan_again; } return 0; } /* * A not-so-good version fls64. No fascinating optimization since * no one except parse_size use it */ static int fls64(u64 x) { int i; for (i = 0; i <64; i++) if (x << i & (1ULL << 63)) return 64 - i; return 64 - i; } u64 parse_size(char *s) { char c; char *endptr; u64 mult = 1; u64 ret; if (!s) { fprintf(stderr, "ERROR: Size value is empty\n"); exit(1); } if (s[0] == '-') { fprintf(stderr, "ERROR: Size value '%s' is less equal than 0\n", s); exit(1); } ret = strtoull(s, &endptr, 10); if (endptr == s) { fprintf(stderr, "ERROR: Size value '%s' is invalid\n", s); exit(1); } if (endptr[0] && endptr[1]) { fprintf(stderr, "ERROR: Illegal suffix contains character '%c' in wrong position\n", endptr[1]); exit(1); } /* * strtoll returns LLONG_MAX when overflow, if this happens, * need to call strtoull to get the real size */ if (errno == ERANGE && ret == ULLONG_MAX) { fprintf(stderr, "ERROR: Size value '%s' is too large for u64\n", s); exit(1); } if (endptr[0]) { c = tolower(endptr[0]); switch (c) { case 'e': mult *= 1024; /* fallthrough */ case 'p': mult *= 1024; /* fallthrough */ case 't': mult *= 1024; /* fallthrough */ case 'g': mult *= 1024; /* fallthrough */ case 'm': mult *= 1024; /* fallthrough */ case 'k': mult *= 1024; /* fallthrough */ case 'b': break; default: fprintf(stderr, "ERROR: Unknown size descriptor '%c'\n", c); exit(1); } } /* Check whether ret * mult overflow */ if (fls64(ret) + fls64(mult) - 1 > 64) { fprintf(stderr, "ERROR: Size value '%s' is too large for u64\n", s); exit(1); } ret *= mult; return ret; } int open_file_or_dir3(const char *fname, DIR **dirstream, int open_flags) { int ret; struct stat st; int fd; ret = stat(fname, &st); if (ret < 0) { return -1; } if (S_ISDIR(st.st_mode)) { *dirstream = opendir(fname); if (!*dirstream) return -1; fd = dirfd(*dirstream); } else if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) { fd = open(fname, open_flags); } else { /* * we set this on purpose, in case the caller output * strerror(errno) as success */ errno = EINVAL; return -1; } if (fd < 0) { fd = -1; if (*dirstream) closedir(*dirstream); } return fd; } int open_file_or_dir(const char *fname, DIR **dirstream) { return open_file_or_dir3(fname, dirstream, O_RDWR); } void close_file_or_dir(int fd, DIR *dirstream) { if (dirstream) closedir(dirstream); else if (fd >= 0) close(fd); } int get_device_info(int fd, u64 devid, struct btrfs_ioctl_dev_info_args *di_args) { int ret; di_args->devid = devid; memset(&di_args->uuid, '\0', sizeof(di_args->uuid)); ret = ioctl(fd, BTRFS_IOC_DEV_INFO, di_args); return ret ? -errno : 0; } /* * For a given path, fill in the ioctl fs_ and info_ args. * If the path is a btrfs mountpoint, fill info for all devices. * If the path is a btrfs device, fill in only that device. * * The path provided must be either on a mounted btrfs fs, * or be a mounted btrfs device. * * Returns 0 on success, or a negative errno. */ int get_fs_info(char *path, struct btrfs_ioctl_fs_info_args *fi_args, struct btrfs_ioctl_dev_info_args **di_ret) { int fd = -1; int ret = 0; int ndevs = 0; int i = 0; struct btrfs_fs_devices *fs_devices_mnt = NULL; struct btrfs_ioctl_dev_info_args *di_args; char mp[BTRFS_PATH_NAME_MAX + 1]; DIR *dirstream = NULL; memset(fi_args, 0, sizeof(*fi_args)); if (is_block_device(path)) { struct btrfs_super_block *disk_super; char buf[BTRFS_SUPER_INFO_SIZE]; u64 devid; /* Ensure it's mounted, then set path to the mountpoint */ fd = open(path, O_RDONLY); if (fd < 0) { ret = -errno; fprintf(stderr, "Couldn't open %s: %s\n", path, strerror(errno)); goto out; } ret = check_mounted_where(fd, path, mp, sizeof(mp), &fs_devices_mnt); if (!ret) { ret = -EINVAL; goto out; } if (ret < 0) goto out; path = mp; /* Only fill in this one device */ fi_args->num_devices = 1; disk_super = (struct btrfs_super_block *)buf; ret = btrfs_read_dev_super(fd, disk_super, BTRFS_SUPER_INFO_OFFSET, 0); if (ret < 0) { ret = -EIO; goto out; } devid = btrfs_stack_device_id(&disk_super->dev_item); fi_args->max_id = devid; i = devid; memcpy(fi_args->fsid, fs_devices_mnt->fsid, BTRFS_FSID_SIZE); close(fd); } /* at this point path must not be for a block device */ fd = open_file_or_dir(path, &dirstream); if (fd < 0) { ret = -errno; goto out; } /* fill in fi_args if not just a single device */ if (fi_args->num_devices != 1) { ret = ioctl(fd, BTRFS_IOC_FS_INFO, fi_args); if (ret < 0) { ret = -errno; goto out; } } if (!fi_args->num_devices) goto out; di_args = *di_ret = malloc((fi_args->num_devices) * sizeof(*di_args)); if (!di_args) { ret = -errno; goto out; } for (; i <= fi_args->max_id; ++i) { BUG_ON(ndevs >= fi_args->num_devices); ret = get_device_info(fd, i, &di_args[ndevs]); if (ret == -ENODEV) continue; if (ret) goto out; ndevs++; } /* * only when the only dev we wanted to find is not there then * let any error be returned */ if (fi_args->num_devices != 1) { BUG_ON(ndevs == 0); ret = 0; } out: close_file_or_dir(fd, dirstream); return ret; } #define isoctal(c) (((c) & ~7) == '0') static inline void translate(char *f, char *t) { while (*f != '\0') { if (*f == '\\' && isoctal(f[1]) && isoctal(f[2]) && isoctal(f[3])) { *t++ = 64*(f[1] & 7) + 8*(f[2] & 7) + (f[3] & 7); f += 4; } else *t++ = *f++; } *t = '\0'; return; } /* * Checks if the swap device. * Returns 1 if swap device, < 0 on error or 0 if not swap device. */ static int is_swap_device(const char *file) { FILE *f; struct stat st_buf; dev_t dev; ino_t ino = 0; char tmp[PATH_MAX]; char buf[PATH_MAX]; char *cp; int ret = 0; if (stat(file, &st_buf) < 0) return -errno; if (S_ISBLK(st_buf.st_mode)) dev = st_buf.st_rdev; else if (S_ISREG(st_buf.st_mode)) { dev = st_buf.st_dev; ino = st_buf.st_ino; } else return 0; if ((f = fopen("/proc/swaps", "r")) == NULL) return 0; /* skip the first line */ if (fgets(tmp, sizeof(tmp), f) == NULL) goto out; while (fgets(tmp, sizeof(tmp), f) != NULL) { if ((cp = strchr(tmp, ' ')) != NULL) *cp = '\0'; if ((cp = strchr(tmp, '\t')) != NULL) *cp = '\0'; translate(tmp, buf); if (stat(buf, &st_buf) != 0) continue; if (S_ISBLK(st_buf.st_mode)) { if (dev == st_buf.st_rdev) { ret = 1; break; } } else if (S_ISREG(st_buf.st_mode)) { if (dev == st_buf.st_dev && ino == st_buf.st_ino) { ret = 1; break; } } } out: fclose(f); return ret; } /* * Check for existing filesystem or partition table on device. * Returns: * 1 for existing fs or partition * 0 for nothing found * -1 for internal error */ static int check_overwrite( char *device) { const char *type; blkid_probe pr = NULL; int ret; blkid_loff_t size; if (!device || !*device) return 0; ret = -1; /* will reset on success of all setup calls */ pr = blkid_new_probe_from_filename(device); if (!pr) goto out; size = blkid_probe_get_size(pr); if (size < 0) goto out; /* nothing to overwrite on a 0-length device */ if (size == 0) { ret = 0; goto out; } ret = blkid_probe_enable_partitions(pr, 1); if (ret < 0) goto out; ret = blkid_do_fullprobe(pr); if (ret < 0) goto out; /* * Blkid returns 1 for nothing found and 0 when it finds a signature, * but we want the exact opposite, so reverse the return value here. * * In addition print some useful diagnostics about what actually is * on the device. */ if (ret) { ret = 0; goto out; } if (!blkid_probe_lookup_value(pr, "TYPE", &type, NULL)) { fprintf(stderr, "%s appears to contain an existing " "filesystem (%s).\n", device, type); } else if (!blkid_probe_lookup_value(pr, "PTTYPE", &type, NULL)) { fprintf(stderr, "%s appears to contain a partition " "table (%s).\n", device, type); } else { fprintf(stderr, "%s appears to contain something weird " "according to blkid\n", device); } ret = 1; out: if (pr) blkid_free_probe(pr); if (ret == -1) fprintf(stderr, "probe of %s failed, cannot detect " "existing filesystem.\n", device); return ret; } int test_num_disk_vs_raid(u64 metadata_profile, u64 data_profile, u64 dev_cnt, int mixed, char *estr) { size_t sz = 100; u64 allowed = 0; switch (dev_cnt) { default: case 4: allowed |= BTRFS_BLOCK_GROUP_RAID10; case 3: allowed |= BTRFS_BLOCK_GROUP_RAID6; case 2: allowed |= BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID5; break; case 1: allowed |= BTRFS_BLOCK_GROUP_DUP; } if (metadata_profile & ~allowed) { snprintf(estr, sz, "unable to create FS with metadata " "profile %llu (have %llu devices)\n", metadata_profile, dev_cnt); return 1; } if (data_profile & ~allowed) { snprintf(estr, sz, "unable to create FS with data " "profile %llu (have %llu devices)\n", metadata_profile, dev_cnt); return 1; } if (!mixed && (data_profile & BTRFS_BLOCK_GROUP_DUP)) { snprintf(estr, sz, "dup for data is allowed only in mixed mode"); return 1; } return 0; } /* Check if disk is suitable for btrfs * returns: * 1: something is wrong, estr provides the error * 0: all is fine */ int test_dev_for_mkfs(char *file, int force_overwrite, char *estr) { int ret, fd; size_t sz = 100; struct stat st; ret = is_swap_device(file); if (ret < 0) { snprintf(estr, sz, "error checking %s status: %s\n", file, strerror(-ret)); return 1; } if (ret == 1) { snprintf(estr, sz, "%s is a swap device\n", file); return 1; } if (!force_overwrite) { if (check_overwrite(file)) { snprintf(estr, sz, "Use the -f option to force overwrite.\n"); return 1; } } ret = check_mounted(file); if (ret < 0) { snprintf(estr, sz, "error checking %s mount status\n", file); return 1; } if (ret == 1) { snprintf(estr, sz, "%s is mounted\n", file); return 1; } /* check if the device is busy */ fd = open(file, O_RDWR|O_EXCL); if (fd < 0) { snprintf(estr, sz, "unable to open %s: %s\n", file, strerror(errno)); return 1; } if (fstat(fd, &st)) { snprintf(estr, sz, "unable to stat %s: %s\n", file, strerror(errno)); close(fd); return 1; } if (!S_ISBLK(st.st_mode)) { fprintf(stderr, "'%s' is not a block device\n", file); close(fd); return 1; } close(fd); return 0; } int btrfs_scan_lblkid() { int fd = -1; int ret; u64 num_devices; struct btrfs_fs_devices *tmp_devices; blkid_dev_iterate iter = NULL; blkid_dev dev = NULL; blkid_cache cache = NULL; char path[PATH_MAX]; if (btrfs_scan_done) return 0; if (blkid_get_cache(&cache, 0) < 0) { printf("ERROR: lblkid cache get failed\n"); return 1; } blkid_probe_all(cache); iter = blkid_dev_iterate_begin(cache); blkid_dev_set_search(iter, "TYPE", "btrfs"); while (blkid_dev_next(iter, &dev) == 0) { dev = blkid_verify(cache, dev); if (!dev) continue; /* if we are here its definitely a btrfs disk*/ strncpy(path, blkid_dev_devname(dev), PATH_MAX); fd = open(path, O_RDONLY); if (fd < 0) { printf("ERROR: could not open %s\n", path); continue; } ret = btrfs_scan_one_device(fd, path, &tmp_devices, &num_devices, BTRFS_SUPER_INFO_OFFSET, 0); if (ret) { printf("ERROR: could not scan %s\n", path); close (fd); continue; } close(fd); } blkid_dev_iterate_end(iter); blkid_put_cache(cache); btrfs_scan_done = 1; return 0; } int is_vol_small(char *file) { int fd = -1; int e; struct stat st; u64 size; fd = open(file, O_RDONLY); if (fd < 0) return -errno; if (fstat(fd, &st) < 0) { e = -errno; close(fd); return e; } size = btrfs_device_size(fd, &st); if (size == 0) { close(fd); return -1; } if (size < BTRFS_MKFS_SMALL_VOLUME_SIZE) { close(fd); return 1; } else { close(fd); return 0; } } /* * This reads a line from the stdin and only returns non-zero if the * first whitespace delimited token is a case insensitive match with yes * or y. */ int ask_user(char *question) { char buf[30] = {0,}; char *saveptr = NULL; char *answer; printf("%s [y/N]: ", question); return fgets(buf, sizeof(buf) - 1, stdin) && (answer = strtok_r(buf, " \t\n\r", &saveptr)) && (!strcasecmp(answer, "yes") || !strcasecmp(answer, "y")); } /* * For a given: * - file or directory return the containing tree root id * - subvolume return its own tree id * - BTRFS_EMPTY_SUBVOL_DIR_OBJECTID (directory with ino == 2) the result is * undefined and function returns -1 */ int lookup_ino_rootid(int fd, u64 *rootid) { struct btrfs_ioctl_ino_lookup_args args; int ret; int e; memset(&args, 0, sizeof(args)); args.treeid = 0; args.objectid = BTRFS_FIRST_FREE_OBJECTID; ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args); e = errno; if (ret) { fprintf(stderr, "ERROR: Failed to lookup root id - %s\n", strerror(e)); return ret; } *rootid = args.treeid; return 0; } /* * return 0 if a btrfs mount point is found * return 1 if a mount point is found but not btrfs * return <0 if something goes wrong */ int find_mount_root(const char *path, char **mount_root) { FILE *mnttab; int fd; struct mntent *ent; int len; int ret; int not_btrfs = 1; int longest_matchlen = 0; char *longest_match = NULL; fd = open(path, O_RDONLY | O_NOATIME); if (fd < 0) return -errno; close(fd); mnttab = setmntent("/proc/self/mounts", "r"); if (!mnttab) return -errno; while ((ent = getmntent(mnttab))) { len = strlen(ent->mnt_dir); if (strncmp(ent->mnt_dir, path, len) == 0) { /* match found and use the latest match */ if (longest_matchlen <= len) { free(longest_match); longest_matchlen = len; longest_match = strdup(ent->mnt_dir); not_btrfs = strcmp(ent->mnt_type, "btrfs"); } } } endmntent(mnttab); if (!longest_match) return -ENOENT; if (not_btrfs) { free(longest_match); return 1; } ret = 0; *mount_root = realpath(longest_match, NULL); if (!*mount_root) ret = -errno; free(longest_match); return ret; } int test_minimum_size(const char *file, u32 leafsize) { int fd; struct stat statbuf; fd = open(file, O_RDONLY); if (fd < 0) return -errno; if (stat(file, &statbuf) < 0) { close(fd); return -errno; } if (btrfs_device_size(fd, &statbuf) < btrfs_min_dev_size(leafsize)) { close(fd); return 1; } close(fd); return 0; } /* * test if name is a correct subvolume name * this function return * 0-> name is not a correct subvolume name * 1-> name is a correct subvolume name */ int test_issubvolname(const char *name) { return name[0] != '\0' && !strchr(name, '/') && strcmp(name, ".") && strcmp(name, ".."); } /* * test if path is a directory * this function return * 0-> path exists but it is not a directory * 1-> path exists and it is a directory * -1 -> path is unaccessible */ int test_isdir(const char *path) { struct stat st; int ret; ret = stat(path, &st); if(ret < 0 ) return -1; return S_ISDIR(st.st_mode); } void units_set_mode(unsigned *units, unsigned mode) { unsigned base = *units & UNITS_MODE_MASK; *units = base | mode; } void units_set_base(unsigned *units, unsigned base) { unsigned mode = *units & ~UNITS_MODE_MASK; *units = base | mode; } int find_next_key(struct btrfs_path *path, struct btrfs_key *key) { int level; for (level = 0; level < BTRFS_MAX_LEVEL; level++) { if (!path->nodes[level]) break; if (path->slots[level] + 1 >= btrfs_header_nritems(path->nodes[level])) continue; if (level == 0) btrfs_item_key_to_cpu(path->nodes[level], key, path->slots[level] + 1); else btrfs_node_key_to_cpu(path->nodes[level], key, path->slots[level] + 1); return 0; } return 1; } partclone-0.2.86/src/btrfs/utils.h000066400000000000000000000137061262102574200170260ustar00rootroot00000000000000/* * Copyright (C) 2007 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. */ #ifndef __UTILS__ #define __UTILS__ #include #include "ctree.h" #include #define BTRFS_MKFS_SYSTEM_GROUP_SIZE (4 * 1024 * 1024) #define BTRFS_MKFS_SMALL_VOLUME_SIZE (1024 * 1024 * 1024) #define BTRFS_SCAN_MOUNTED (1ULL << 0) #define BTRFS_SCAN_LBLKID (1ULL << 1) #define BTRFS_UPDATE_KERNEL 1 #define BTRFS_ARG_UNKNOWN 0 #define BTRFS_ARG_MNTPOINT 1 #define BTRFS_ARG_UUID 2 #define BTRFS_ARG_BLKDEV 3 #define BTRFS_UUID_UNPARSED_SIZE 37 #define ARGV0_BUF_SIZE PATH_MAX int check_argc_exact(int nargs, int expected); int check_argc_min(int nargs, int expected); int check_argc_max(int nargs, int expected); void fixup_argv0(char **argv, const char *token); void set_argv0(char **argv); /* * Output modes of size */ #define UNITS_RESERVED (0) #define UNITS_BYTES (1) #define UNITS_KBYTES (2) #define UNITS_MBYTES (3) #define UNITS_GBYTES (4) #define UNITS_TBYTES (5) #define UNITS_RAW (1U << UNITS_MODE_SHIFT) #define UNITS_BINARY (2U << UNITS_MODE_SHIFT) #define UNITS_DECIMAL (3U << UNITS_MODE_SHIFT) #define UNITS_MODE_MASK ((1U << UNITS_MODE_SHIFT) - 1) #define UNITS_MODE_SHIFT (8) #define UNITS_HUMAN_BINARY (UNITS_BINARY) #define UNITS_HUMAN_DECIMAL (UNITS_DECIMAL) #define UNITS_HUMAN (UNITS_HUMAN_BINARY) #define UNITS_DEFAULT (UNITS_HUMAN) void units_set_mode(unsigned *units, unsigned mode); void units_set_base(unsigned *units, unsigned base); int make_btrfs(int fd, const char *device, const char *label, char *fs_uuid, u64 blocks[6], u64 num_bytes, u32 nodesize, u32 leafsize, u32 sectorsize, u32 stripesize, u64 features); int btrfs_make_root_dir(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 objectid); int btrfs_prepare_device(int fd, char *file, int zero_end, u64 *block_count_ret, u64 max_block_count, int *mixed, int discard); int btrfs_add_to_fsid(struct btrfs_trans_handle *trans, struct btrfs_root *root, int fd, char *path, u64 block_count, u32 io_width, u32 io_align, u32 sectorsize); int btrfs_scan_for_fsid(int run_ioctls); int btrfs_register_one_device(const char *fname); int btrfs_register_all_devices(void); char *canonicalize_dm_name(const char *ptname); char *canonicalize_path(const char *path); int check_mounted(const char *devicename); int check_mounted_where(int fd, const char *file, char *where, int size, struct btrfs_fs_devices **fs_devices_mnt); int btrfs_device_already_in_root(struct btrfs_root *root, int fd, int super_offset); int pretty_size_snprintf(u64 size, char *str, size_t str_bytes, unsigned unit_mode); #define pretty_size(size) pretty_size_mode(size, UNITS_DEFAULT) #define pretty_size_mode(size, mode) \ ({ \ static __thread char _str[32]; \ (void)pretty_size_snprintf((size), _str, sizeof(_str), (mode)); \ _str; \ }) int get_mountpt(char *dev, char *mntpt, size_t size); int btrfs_scan_block_devices(int run_ioctl); u64 parse_size(char *s); u64 arg_strtou64(const char *str); int open_file_or_dir(const char *fname, DIR **dirstream); int open_file_or_dir3(const char *fname, DIR **dirstream, int open_flags); void close_file_or_dir(int fd, DIR *dirstream); int get_fs_info(char *path, struct btrfs_ioctl_fs_info_args *fi_args, struct btrfs_ioctl_dev_info_args **di_ret); int get_label(const char *btrfs_dev, char *label); int set_label(const char *btrfs_dev, const char *label); char *__strncpy__null(char *dest, const char *src, size_t n); int is_block_device(const char *file); int is_mount_point(const char *file); int open_path_or_dev_mnt(const char *path, DIR **dirstream); u64 btrfs_device_size(int fd, struct stat *st); /* Helper to always get proper size of the destination string */ #define strncpy_null(dest, src) __strncpy__null(dest, src, sizeof(dest)) int test_dev_for_mkfs(char *file, int force_overwrite, char *estr); int get_label_mounted(const char *mount_path, char *labelp); int test_num_disk_vs_raid(u64 metadata_profile, u64 data_profile, u64 dev_cnt, int mixed, char *estr); int is_vol_small(char *file); int csum_tree_block(struct btrfs_root *root, struct extent_buffer *buf, int verify); int ask_user(char *question); int lookup_ino_rootid(int fd, u64 *rootid); int btrfs_scan_lblkid(void); int get_btrfs_mount(const char *dev, char *mp, size_t mp_size); int find_mount_root(const char *path, char **mount_root); int get_device_info(int fd, u64 devid, struct btrfs_ioctl_dev_info_args *di_args); int test_uuid_unique(char *fs_uuid); int test_minimum_size(const char *file, u32 leafsize); int test_issubvolname(const char *name); int test_isdir(const char *path); /* * Btrfs minimum size calculation is complicated, it should include at least: * 1. system group size * 2. minimum global block reserve * 3. metadata used at mkfs * 4. space reservation to create uuid for first mount. * Also, raid factor should also be taken into consideration. * To avoid the overkill calculation, (system group + global block rsv) * 2 * for *EACH* device should be good enough. */ static inline u64 btrfs_min_global_blk_rsv_size(u32 leafsize) { return leafsize << 10; } static inline u64 btrfs_min_dev_size(u32 leafsize) { return 2 * (BTRFS_MKFS_SYSTEM_GROUP_SIZE + btrfs_min_global_blk_rsv_size(leafsize)); } int find_next_key(struct btrfs_path *path, struct btrfs_key *key); #endif partclone-0.2.86/src/btrfs/uuid-tree.c000066400000000000000000000060031262102574200175540ustar00rootroot00000000000000/* * Copyright (C) STRATO AG 2013. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. */ #include #include #include #include #include "ctree.h" #include "transaction.h" #include "disk-io.h" #include "print-tree.h" static void btrfs_uuid_to_key(const u8 *uuid, u64 *key_objectid, u64 *key_offset) { *key_objectid = get_unaligned_le64(uuid); *key_offset = get_unaligned_le64(uuid + sizeof(u64)); } /* return -ENOENT for !found, < 0 for errors, or 0 if an item was found */ static int btrfs_uuid_tree_lookup_any(int fd, const u8 *uuid, u8 type, u64 *subid) { int ret; u64 key_objectid = 0; u64 key_offset; struct btrfs_ioctl_search_args search_arg; struct btrfs_ioctl_search_header *search_header; u32 item_size; __le64 lesubid; btrfs_uuid_to_key(uuid, &key_objectid, &key_offset); memset(&search_arg, 0, sizeof(search_arg)); search_arg.key.tree_id = BTRFS_UUID_TREE_OBJECTID; search_arg.key.min_objectid = key_objectid; search_arg.key.max_objectid = key_objectid; search_arg.key.min_type = type; search_arg.key.max_type = type; search_arg.key.min_offset = key_offset; search_arg.key.max_offset = key_offset; search_arg.key.max_transid = (u64)-1; search_arg.key.nr_items = 1; ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &search_arg); if (ret < 0) { fprintf(stderr, "ioctl(BTRFS_IOC_TREE_SEARCH, uuid, key %016llx, UUID_KEY, %016llx) ret=%d, error: %s\n", (unsigned long long)key_objectid, (unsigned long long)key_offset, ret, strerror(errno)); ret = -ENOENT; goto out; } if (search_arg.key.nr_items < 1) { ret = -ENOENT; goto out; } search_header = (struct btrfs_ioctl_search_header *)(search_arg.buf); item_size = search_header->len; if ((item_size & (sizeof(u64) - 1)) || item_size == 0) { printf("btrfs: uuid item with illegal size %lu!\n", (unsigned long)item_size); ret = -ENOENT; goto out; } else { ret = 0; } /* return first stored id */ memcpy(&lesubid, search_header + 1, sizeof(lesubid)); *subid = le64_to_cpu(lesubid); out: return ret; } int btrfs_lookup_uuid_subvol_item(int fd, const u8 *uuid, u64 *subvol_id) { return btrfs_uuid_tree_lookup_any(fd, uuid, BTRFS_UUID_KEY_SUBVOL, subvol_id); } int btrfs_lookup_uuid_received_subvol_item(int fd, const u8 *uuid, u64 *subvol_id) { return btrfs_uuid_tree_lookup_any(fd, uuid, BTRFS_UUID_KEY_RECEIVED_SUBVOL, subvol_id); } partclone-0.2.86/src/btrfs/version.h000066400000000000000000000006351262102574200173500ustar00rootroot00000000000000/* NOTE: this file is autogenerated by version.sh, do not edit */ #ifndef __BUILD_VERSION #define __BUILD_VERSION #define BTRFS_LIB_MAJOR 0 #define BTRFS_LIB_MINOR 1 #define BTRFS_LIB_PATCHLEVEL 1 #define BTRFS_LIB_VERSION ( BTRFS_LIB_MAJOR * 10000 + \ BTRFS_LIB_MINOR * 100 + \ BTRFS_LIB_PATCHLEVEL ) #define BTRFS_BUILD_VERSION "Btrfs v3.17.3" #endif partclone-0.2.86/src/btrfs/volumes.c000066400000000000000000001475721262102574200173640ustar00rootroot00000000000000/* * Copyright (C) 2007 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. */ #define _XOPEN_SOURCE 600 #define __USE_XOPEN2K #include #include #include #include #include #include #include #include "ctree.h" #include "disk-io.h" #include "transaction.h" #include "print-tree.h" #include "volumes.h" #include "math.h" struct stripe { struct btrfs_device *dev; u64 physical; }; static inline int nr_parity_stripes(struct map_lookup *map) { if (map->type & BTRFS_BLOCK_GROUP_RAID5) return 1; else if (map->type & BTRFS_BLOCK_GROUP_RAID6) return 2; else return 0; } static inline int nr_data_stripes(struct map_lookup *map) { return map->num_stripes - nr_parity_stripes(map); } #define is_parity_stripe(x) ( ((x) == BTRFS_RAID5_P_STRIPE) || ((x) == BTRFS_RAID6_Q_STRIPE) ) static LIST_HEAD(fs_uuids); static struct btrfs_device *__find_device(struct list_head *head, u64 devid, u8 *uuid) { struct btrfs_device *dev; struct list_head *cur; list_for_each(cur, head) { dev = list_entry(cur, struct btrfs_device, dev_list); if (dev->devid == devid && !memcmp(dev->uuid, uuid, BTRFS_UUID_SIZE)) { return dev; } } return NULL; } static struct btrfs_fs_devices *find_fsid(u8 *fsid) { struct list_head *cur; struct btrfs_fs_devices *fs_devices; list_for_each(cur, &fs_uuids) { fs_devices = list_entry(cur, struct btrfs_fs_devices, list); if (memcmp(fsid, fs_devices->fsid, BTRFS_FSID_SIZE) == 0) return fs_devices; } return NULL; } static int device_list_add(const char *path, struct btrfs_super_block *disk_super, u64 devid, struct btrfs_fs_devices **fs_devices_ret) { struct btrfs_device *device; struct btrfs_fs_devices *fs_devices; u64 found_transid = btrfs_super_generation(disk_super); fs_devices = find_fsid(disk_super->fsid); if (!fs_devices) { fs_devices = kzalloc(sizeof(*fs_devices), GFP_NOFS); if (!fs_devices) return -ENOMEM; INIT_LIST_HEAD(&fs_devices->devices); list_add(&fs_devices->list, &fs_uuids); memcpy(fs_devices->fsid, disk_super->fsid, BTRFS_FSID_SIZE); fs_devices->latest_devid = devid; fs_devices->latest_trans = found_transid; fs_devices->lowest_devid = (u64)-1; device = NULL; } else { device = __find_device(&fs_devices->devices, devid, disk_super->dev_item.uuid); } if (!device) { device = kzalloc(sizeof(*device), GFP_NOFS); if (!device) { /* we can safely leave the fs_devices entry around */ return -ENOMEM; } device->fd = -1; device->devid = devid; device->generation = found_transid; memcpy(device->uuid, disk_super->dev_item.uuid, BTRFS_UUID_SIZE); device->name = kstrdup(path, GFP_NOFS); if (!device->name) { kfree(device); return -ENOMEM; } device->label = kstrdup(disk_super->label, GFP_NOFS); if (!device->label) { kfree(device->name); kfree(device); return -ENOMEM; } device->total_devs = btrfs_super_num_devices(disk_super); device->super_bytes_used = btrfs_super_bytes_used(disk_super); device->total_bytes = btrfs_stack_device_total_bytes(&disk_super->dev_item); device->bytes_used = btrfs_stack_device_bytes_used(&disk_super->dev_item); list_add(&device->dev_list, &fs_devices->devices); device->fs_devices = fs_devices; } else if (!device->name || strcmp(device->name, path)) { char *name = strdup(path); if (!name) return -ENOMEM; kfree(device->name); device->name = name; } if (found_transid > fs_devices->latest_trans) { fs_devices->latest_devid = devid; fs_devices->latest_trans = found_transid; } if (fs_devices->lowest_devid > devid) { fs_devices->lowest_devid = devid; } *fs_devices_ret = fs_devices; return 0; } int btrfs_close_devices(struct btrfs_fs_devices *fs_devices) { struct btrfs_fs_devices *seed_devices; struct btrfs_device *device; again: while (!list_empty(&fs_devices->devices)) { device = list_entry(fs_devices->devices.next, struct btrfs_device, dev_list); if (device->fd != -1) { fsync(device->fd); if (posix_fadvise(device->fd, 0, 0, POSIX_FADV_DONTNEED)) fprintf(stderr, "Warning, could not drop caches\n"); close(device->fd); device->fd = -1; } device->writeable = 0; list_del(&device->dev_list); /* free the memory */ free(device->name); free(device->label); free(device); } seed_devices = fs_devices->seed; fs_devices->seed = NULL; if (seed_devices) { struct btrfs_fs_devices *orig; orig = fs_devices; fs_devices = seed_devices; list_del(&orig->list); free(orig); goto again; } else { list_del(&fs_devices->list); free(fs_devices); } return 0; } int btrfs_open_devices(struct btrfs_fs_devices *fs_devices, int flags) { int fd; struct list_head *head = &fs_devices->devices; struct list_head *cur; struct btrfs_device *device; int ret; list_for_each(cur, head) { device = list_entry(cur, struct btrfs_device, dev_list); if (!device->name) { printk("no name for device %llu, skip it now\n", device->devid); continue; } fd = open(device->name, flags); if (fd < 0) { ret = -errno; goto fail; } if (posix_fadvise(fd, 0, 0, POSIX_FADV_DONTNEED)) fprintf(stderr, "Warning, could not drop caches\n"); if (device->devid == fs_devices->latest_devid) fs_devices->latest_bdev = fd; if (device->devid == fs_devices->lowest_devid) fs_devices->lowest_bdev = fd; device->fd = fd; if (flags & O_RDWR) device->writeable = 1; } return 0; fail: btrfs_close_devices(fs_devices); return ret; } int btrfs_scan_one_device(int fd, const char *path, struct btrfs_fs_devices **fs_devices_ret, u64 *total_devs, u64 super_offset, int super_recover) { struct btrfs_super_block *disk_super; char *buf; int ret; u64 devid; buf = malloc(4096); if (!buf) { ret = -ENOMEM; goto error; } disk_super = (struct btrfs_super_block *)buf; ret = btrfs_read_dev_super(fd, disk_super, super_offset, super_recover); if (ret < 0) { ret = -EIO; goto error_brelse; } devid = btrfs_stack_device_id(&disk_super->dev_item); if (btrfs_super_flags(disk_super) & BTRFS_SUPER_FLAG_METADUMP) *total_devs = 1; else *total_devs = btrfs_super_num_devices(disk_super); ret = device_list_add(path, disk_super, devid, fs_devices_ret); error_brelse: free(buf); error: return ret; } /* * this uses a pretty simple search, the expectation is that it is * called very infrequently and that a given device has a small number * of extents */ static int find_free_dev_extent(struct btrfs_trans_handle *trans, struct btrfs_device *device, struct btrfs_path *path, u64 num_bytes, u64 *start) { struct btrfs_key key; struct btrfs_root *root = device->dev_root; struct btrfs_dev_extent *dev_extent = NULL; u64 hole_size = 0; u64 last_byte = 0; u64 search_start = root->fs_info->alloc_start; u64 search_end = device->total_bytes; int ret; int slot = 0; int start_found; struct extent_buffer *l; start_found = 0; path->reada = 2; /* FIXME use last free of some kind */ /* we don't want to overwrite the superblock on the drive, * so we make sure to start at an offset of at least 1MB */ search_start = max(BTRFS_BLOCK_RESERVED_1M_FOR_SUPER, search_start); if (search_start >= search_end) { ret = -ENOSPC; goto error; } key.objectid = device->devid; key.offset = search_start; key.type = BTRFS_DEV_EXTENT_KEY; ret = btrfs_search_slot(trans, root, &key, path, 0, 0); if (ret < 0) goto error; ret = btrfs_previous_item(root, path, 0, key.type); if (ret < 0) goto error; l = path->nodes[0]; btrfs_item_key_to_cpu(l, &key, path->slots[0]); while (1) { l = path->nodes[0]; slot = path->slots[0]; if (slot >= btrfs_header_nritems(l)) { ret = btrfs_next_leaf(root, path); if (ret == 0) continue; if (ret < 0) goto error; no_more_items: if (!start_found) { if (search_start >= search_end) { ret = -ENOSPC; goto error; } *start = search_start; start_found = 1; goto check_pending; } *start = last_byte > search_start ? last_byte : search_start; if (search_end <= *start) { ret = -ENOSPC; goto error; } goto check_pending; } btrfs_item_key_to_cpu(l, &key, slot); if (key.objectid < device->devid) goto next; if (key.objectid > device->devid) goto no_more_items; if (key.offset >= search_start && key.offset > last_byte && start_found) { if (last_byte < search_start) last_byte = search_start; hole_size = key.offset - last_byte; if (key.offset > last_byte && hole_size >= num_bytes) { *start = last_byte; goto check_pending; } } if (btrfs_key_type(&key) != BTRFS_DEV_EXTENT_KEY) { goto next; } start_found = 1; dev_extent = btrfs_item_ptr(l, slot, struct btrfs_dev_extent); last_byte = key.offset + btrfs_dev_extent_length(l, dev_extent); next: path->slots[0]++; cond_resched(); } check_pending: /* we have to make sure we didn't find an extent that has already * been allocated by the map tree or the original allocation */ btrfs_release_path(path); BUG_ON(*start < search_start); if (*start + num_bytes > search_end) { ret = -ENOSPC; goto error; } /* check for pending inserts here */ return 0; error: btrfs_release_path(path); return ret; } static int btrfs_alloc_dev_extent(struct btrfs_trans_handle *trans, struct btrfs_device *device, u64 chunk_tree, u64 chunk_objectid, u64 chunk_offset, u64 num_bytes, u64 *start) { int ret; struct btrfs_path *path; struct btrfs_root *root = device->dev_root; struct btrfs_dev_extent *extent; struct extent_buffer *leaf; struct btrfs_key key; path = btrfs_alloc_path(); if (!path) return -ENOMEM; ret = find_free_dev_extent(trans, device, path, num_bytes, start); if (ret) { goto err; } key.objectid = device->devid; key.offset = *start; key.type = BTRFS_DEV_EXTENT_KEY; ret = btrfs_insert_empty_item(trans, root, path, &key, sizeof(*extent)); BUG_ON(ret); leaf = path->nodes[0]; extent = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_dev_extent); btrfs_set_dev_extent_chunk_tree(leaf, extent, chunk_tree); btrfs_set_dev_extent_chunk_objectid(leaf, extent, chunk_objectid); btrfs_set_dev_extent_chunk_offset(leaf, extent, chunk_offset); write_extent_buffer(leaf, root->fs_info->chunk_tree_uuid, (unsigned long)btrfs_dev_extent_chunk_tree_uuid(extent), BTRFS_UUID_SIZE); btrfs_set_dev_extent_length(leaf, extent, num_bytes); btrfs_mark_buffer_dirty(leaf); err: btrfs_free_path(path); return ret; } static int find_next_chunk(struct btrfs_root *root, u64 objectid, u64 *offset) { struct btrfs_path *path; int ret; struct btrfs_key key; struct btrfs_chunk *chunk; struct btrfs_key found_key; path = btrfs_alloc_path(); BUG_ON(!path); key.objectid = objectid; key.offset = (u64)-1; key.type = BTRFS_CHUNK_ITEM_KEY; ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); if (ret < 0) goto error; BUG_ON(ret == 0); ret = btrfs_previous_item(root, path, 0, BTRFS_CHUNK_ITEM_KEY); if (ret) { *offset = 0; } else { btrfs_item_key_to_cpu(path->nodes[0], &found_key, path->slots[0]); if (found_key.objectid != objectid) *offset = 0; else { chunk = btrfs_item_ptr(path->nodes[0], path->slots[0], struct btrfs_chunk); *offset = found_key.offset + btrfs_chunk_length(path->nodes[0], chunk); } } ret = 0; error: btrfs_free_path(path); return ret; } static int find_next_devid(struct btrfs_root *root, struct btrfs_path *path, u64 *objectid) { int ret; struct btrfs_key key; struct btrfs_key found_key; key.objectid = BTRFS_DEV_ITEMS_OBJECTID; key.type = BTRFS_DEV_ITEM_KEY; key.offset = (u64)-1; ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); if (ret < 0) goto error; BUG_ON(ret == 0); ret = btrfs_previous_item(root, path, BTRFS_DEV_ITEMS_OBJECTID, BTRFS_DEV_ITEM_KEY); if (ret) { *objectid = 1; } else { btrfs_item_key_to_cpu(path->nodes[0], &found_key, path->slots[0]); *objectid = found_key.offset + 1; } ret = 0; error: btrfs_release_path(path); return ret; } /* * the device information is stored in the chunk root * the btrfs_device struct should be fully filled in */ int btrfs_add_device(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_device *device) { int ret; struct btrfs_path *path; struct btrfs_dev_item *dev_item; struct extent_buffer *leaf; struct btrfs_key key; unsigned long ptr; u64 free_devid = 0; root = root->fs_info->chunk_root; path = btrfs_alloc_path(); if (!path) return -ENOMEM; ret = find_next_devid(root, path, &free_devid); if (ret) goto out; key.objectid = BTRFS_DEV_ITEMS_OBJECTID; key.type = BTRFS_DEV_ITEM_KEY; key.offset = free_devid; ret = btrfs_insert_empty_item(trans, root, path, &key, sizeof(*dev_item)); if (ret) goto out; leaf = path->nodes[0]; dev_item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_dev_item); device->devid = free_devid; btrfs_set_device_id(leaf, dev_item, device->devid); btrfs_set_device_generation(leaf, dev_item, 0); btrfs_set_device_type(leaf, dev_item, device->type); btrfs_set_device_io_align(leaf, dev_item, device->io_align); btrfs_set_device_io_width(leaf, dev_item, device->io_width); btrfs_set_device_sector_size(leaf, dev_item, device->sector_size); btrfs_set_device_total_bytes(leaf, dev_item, device->total_bytes); btrfs_set_device_bytes_used(leaf, dev_item, device->bytes_used); btrfs_set_device_group(leaf, dev_item, 0); btrfs_set_device_seek_speed(leaf, dev_item, 0); btrfs_set_device_bandwidth(leaf, dev_item, 0); btrfs_set_device_start_offset(leaf, dev_item, 0); ptr = (unsigned long)btrfs_device_uuid(dev_item); write_extent_buffer(leaf, device->uuid, ptr, BTRFS_UUID_SIZE); ptr = (unsigned long)btrfs_device_fsid(dev_item); write_extent_buffer(leaf, root->fs_info->fsid, ptr, BTRFS_UUID_SIZE); btrfs_mark_buffer_dirty(leaf); ret = 0; out: btrfs_free_path(path); return ret; } int btrfs_update_device(struct btrfs_trans_handle *trans, struct btrfs_device *device) { int ret; struct btrfs_path *path; struct btrfs_root *root; struct btrfs_dev_item *dev_item; struct extent_buffer *leaf; struct btrfs_key key; root = device->dev_root->fs_info->chunk_root; path = btrfs_alloc_path(); if (!path) return -ENOMEM; key.objectid = BTRFS_DEV_ITEMS_OBJECTID; key.type = BTRFS_DEV_ITEM_KEY; key.offset = device->devid; ret = btrfs_search_slot(trans, root, &key, path, 0, 1); if (ret < 0) goto out; if (ret > 0) { ret = -ENOENT; goto out; } leaf = path->nodes[0]; dev_item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_dev_item); btrfs_set_device_id(leaf, dev_item, device->devid); btrfs_set_device_type(leaf, dev_item, device->type); btrfs_set_device_io_align(leaf, dev_item, device->io_align); btrfs_set_device_io_width(leaf, dev_item, device->io_width); btrfs_set_device_sector_size(leaf, dev_item, device->sector_size); btrfs_set_device_total_bytes(leaf, dev_item, device->total_bytes); btrfs_set_device_bytes_used(leaf, dev_item, device->bytes_used); btrfs_mark_buffer_dirty(leaf); out: btrfs_free_path(path); return ret; } int btrfs_add_system_chunk(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_key *key, struct btrfs_chunk *chunk, int item_size) { struct btrfs_super_block *super_copy = root->fs_info->super_copy; struct btrfs_disk_key disk_key; u32 array_size; u8 *ptr; array_size = btrfs_super_sys_array_size(super_copy); if (array_size + item_size + sizeof(disk_key) > BTRFS_SYSTEM_CHUNK_ARRAY_SIZE) return -EFBIG; ptr = super_copy->sys_chunk_array + array_size; btrfs_cpu_key_to_disk(&disk_key, key); memcpy(ptr, &disk_key, sizeof(disk_key)); ptr += sizeof(disk_key); memcpy(ptr, chunk, item_size); item_size += sizeof(disk_key); btrfs_set_super_sys_array_size(super_copy, array_size + item_size); return 0; } static u64 chunk_bytes_by_type(u64 type, u64 calc_size, int num_stripes, int sub_stripes) { if (type & (BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_DUP)) return calc_size; else if (type & BTRFS_BLOCK_GROUP_RAID10) return calc_size * (num_stripes / sub_stripes); else if (type & BTRFS_BLOCK_GROUP_RAID5) return calc_size * (num_stripes - 1); else if (type & BTRFS_BLOCK_GROUP_RAID6) return calc_size * (num_stripes - 2); else return calc_size * num_stripes; } static u32 find_raid56_stripe_len(u32 data_devices, u32 dev_stripe_target) { /* TODO, add a way to store the preferred stripe size */ return BTRFS_STRIPE_LEN; } /* * btrfs_device_avail_bytes - count bytes available for alloc_chunk * * It is not equal to "device->total_bytes - device->bytes_used". * We do not allocate any chunk in 1M at beginning of device, and not * allowed to allocate any chunk before alloc_start if it is specified. * So search holes from max(1M, alloc_start) to device->total_bytes. */ static int btrfs_device_avail_bytes(struct btrfs_trans_handle *trans, struct btrfs_device *device, u64 *avail_bytes) { struct btrfs_path *path; struct btrfs_root *root = device->dev_root; struct btrfs_key key; struct btrfs_dev_extent *dev_extent = NULL; struct extent_buffer *l; u64 search_start = root->fs_info->alloc_start; u64 search_end = device->total_bytes; u64 extent_end = 0; u64 free_bytes = 0; int ret; int slot = 0; search_start = max(BTRFS_BLOCK_RESERVED_1M_FOR_SUPER, search_start); path = btrfs_alloc_path(); if (!path) return -ENOMEM; key.objectid = device->devid; key.offset = root->fs_info->alloc_start; key.type = BTRFS_DEV_EXTENT_KEY; path->reada = 2; ret = btrfs_search_slot(trans, root, &key, path, 0, 0); if (ret < 0) goto error; ret = btrfs_previous_item(root, path, 0, key.type); if (ret < 0) goto error; while (1) { l = path->nodes[0]; slot = path->slots[0]; if (slot >= btrfs_header_nritems(l)) { ret = btrfs_next_leaf(root, path); if (ret == 0) continue; if (ret < 0) goto error; break; } btrfs_item_key_to_cpu(l, &key, slot); if (key.objectid < device->devid) goto next; if (key.objectid > device->devid) break; if (btrfs_key_type(&key) != BTRFS_DEV_EXTENT_KEY) goto next; if (key.offset > search_end) break; if (key.offset > search_start) free_bytes += key.offset - search_start; dev_extent = btrfs_item_ptr(l, slot, struct btrfs_dev_extent); extent_end = key.offset + btrfs_dev_extent_length(l, dev_extent); if (extent_end > search_start) search_start = extent_end; if (search_start > search_end) break; next: path->slots[0]++; cond_resched(); } if (search_start < search_end) free_bytes += search_end - search_start; *avail_bytes = free_bytes; ret = 0; error: btrfs_free_path(path); return ret; } #define BTRFS_MAX_DEVS(r) ((BTRFS_LEAF_DATA_SIZE(r) \ - sizeof(struct btrfs_item) \ - sizeof(struct btrfs_chunk)) \ / sizeof(struct btrfs_stripe) + 1) #define BTRFS_MAX_DEVS_SYS_CHUNK ((BTRFS_SYSTEM_CHUNK_ARRAY_SIZE \ - 2 * sizeof(struct btrfs_disk_key) \ - 2 * sizeof(struct btrfs_chunk)) \ / sizeof(struct btrfs_stripe) + 1) int btrfs_alloc_chunk(struct btrfs_trans_handle *trans, struct btrfs_root *extent_root, u64 *start, u64 *num_bytes, u64 type) { u64 dev_offset; struct btrfs_fs_info *info = extent_root->fs_info; struct btrfs_root *chunk_root = info->chunk_root; struct btrfs_stripe *stripes; struct btrfs_device *device = NULL; struct btrfs_chunk *chunk; struct list_head private_devs; struct list_head *dev_list = &info->fs_devices->devices; struct list_head *cur; struct map_lookup *map; int min_stripe_size = 1 * 1024 * 1024; u64 calc_size = 8 * 1024 * 1024; u64 min_free; u64 max_chunk_size = 4 * calc_size; u64 avail = 0; u64 max_avail = 0; u64 percent_max; int num_stripes = 1; int max_stripes = 0; int min_stripes = 1; int sub_stripes = 0; int looped = 0; int ret; int index; int stripe_len = BTRFS_STRIPE_LEN; struct btrfs_key key; u64 offset; if (list_empty(dev_list)) { return -ENOSPC; } if (type & (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID5 | BTRFS_BLOCK_GROUP_RAID6 | BTRFS_BLOCK_GROUP_RAID10 | BTRFS_BLOCK_GROUP_DUP)) { if (type & BTRFS_BLOCK_GROUP_SYSTEM) { calc_size = 8 * 1024 * 1024; max_chunk_size = calc_size * 2; min_stripe_size = 1 * 1024 * 1024; max_stripes = BTRFS_MAX_DEVS_SYS_CHUNK; } else if (type & BTRFS_BLOCK_GROUP_DATA) { calc_size = 1024 * 1024 * 1024; max_chunk_size = 10 * calc_size; min_stripe_size = 64 * 1024 * 1024; max_stripes = BTRFS_MAX_DEVS(chunk_root); } else if (type & BTRFS_BLOCK_GROUP_METADATA) { calc_size = 1024 * 1024 * 1024; max_chunk_size = 4 * calc_size; min_stripe_size = 32 * 1024 * 1024; max_stripes = BTRFS_MAX_DEVS(chunk_root); } } if (type & BTRFS_BLOCK_GROUP_RAID1) { num_stripes = min_t(u64, 2, btrfs_super_num_devices(info->super_copy)); if (num_stripes < 2) return -ENOSPC; min_stripes = 2; } if (type & BTRFS_BLOCK_GROUP_DUP) { num_stripes = 2; min_stripes = 2; } if (type & (BTRFS_BLOCK_GROUP_RAID0)) { num_stripes = btrfs_super_num_devices(info->super_copy); if (num_stripes > max_stripes) num_stripes = max_stripes; min_stripes = 2; } if (type & (BTRFS_BLOCK_GROUP_RAID10)) { num_stripes = btrfs_super_num_devices(info->super_copy); if (num_stripes > max_stripes) num_stripes = max_stripes; if (num_stripes < 4) return -ENOSPC; num_stripes &= ~(u32)1; sub_stripes = 2; min_stripes = 4; } if (type & (BTRFS_BLOCK_GROUP_RAID5)) { num_stripes = btrfs_super_num_devices(info->super_copy); if (num_stripes > max_stripes) num_stripes = max_stripes; if (num_stripes < 2) return -ENOSPC; min_stripes = 2; stripe_len = find_raid56_stripe_len(num_stripes - 1, btrfs_super_stripesize(info->super_copy)); } if (type & (BTRFS_BLOCK_GROUP_RAID6)) { num_stripes = btrfs_super_num_devices(info->super_copy); if (num_stripes > max_stripes) num_stripes = max_stripes; if (num_stripes < 3) return -ENOSPC; min_stripes = 3; stripe_len = find_raid56_stripe_len(num_stripes - 2, btrfs_super_stripesize(info->super_copy)); } /* we don't want a chunk larger than 10% of the FS */ percent_max = div_factor(btrfs_super_total_bytes(info->super_copy), 1); max_chunk_size = min(percent_max, max_chunk_size); again: if (chunk_bytes_by_type(type, calc_size, num_stripes, sub_stripes) > max_chunk_size) { calc_size = max_chunk_size; calc_size /= num_stripes; calc_size /= stripe_len; calc_size *= stripe_len; } /* we don't want tiny stripes */ calc_size = max_t(u64, calc_size, min_stripe_size); calc_size /= stripe_len; calc_size *= stripe_len; INIT_LIST_HEAD(&private_devs); cur = dev_list->next; index = 0; if (type & BTRFS_BLOCK_GROUP_DUP) min_free = calc_size * 2; else min_free = calc_size; /* build a private list of devices we will allocate from */ while(index < num_stripes) { device = list_entry(cur, struct btrfs_device, dev_list); ret = btrfs_device_avail_bytes(trans, device, &avail); if (ret) return ret; cur = cur->next; if (avail >= min_free) { list_move_tail(&device->dev_list, &private_devs); index++; if (type & BTRFS_BLOCK_GROUP_DUP) index++; } else if (avail > max_avail) max_avail = avail; if (cur == dev_list) break; } if (index < num_stripes) { list_splice(&private_devs, dev_list); if (index >= min_stripes) { num_stripes = index; if (type & (BTRFS_BLOCK_GROUP_RAID10)) { num_stripes /= sub_stripes; num_stripes *= sub_stripes; } looped = 1; goto again; } if (!looped && max_avail > 0) { looped = 1; calc_size = max_avail; goto again; } return -ENOSPC; } ret = find_next_chunk(chunk_root, BTRFS_FIRST_CHUNK_TREE_OBJECTID, &offset); if (ret) return ret; key.objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID; key.type = BTRFS_CHUNK_ITEM_KEY; key.offset = offset; chunk = kmalloc(btrfs_chunk_item_size(num_stripes), GFP_NOFS); if (!chunk) return -ENOMEM; map = kmalloc(btrfs_map_lookup_size(num_stripes), GFP_NOFS); if (!map) { kfree(chunk); return -ENOMEM; } stripes = &chunk->stripe; *num_bytes = chunk_bytes_by_type(type, calc_size, num_stripes, sub_stripes); index = 0; while(index < num_stripes) { struct btrfs_stripe *stripe; BUG_ON(list_empty(&private_devs)); cur = private_devs.next; device = list_entry(cur, struct btrfs_device, dev_list); /* loop over this device again if we're doing a dup group */ if (!(type & BTRFS_BLOCK_GROUP_DUP) || (index == num_stripes - 1)) list_move_tail(&device->dev_list, dev_list); ret = btrfs_alloc_dev_extent(trans, device, info->chunk_root->root_key.objectid, BTRFS_FIRST_CHUNK_TREE_OBJECTID, key.offset, calc_size, &dev_offset); BUG_ON(ret); device->bytes_used += calc_size; ret = btrfs_update_device(trans, device); BUG_ON(ret); map->stripes[index].dev = device; map->stripes[index].physical = dev_offset; stripe = stripes + index; btrfs_set_stack_stripe_devid(stripe, device->devid); btrfs_set_stack_stripe_offset(stripe, dev_offset); memcpy(stripe->dev_uuid, device->uuid, BTRFS_UUID_SIZE); index++; } BUG_ON(!list_empty(&private_devs)); /* key was set above */ btrfs_set_stack_chunk_length(chunk, *num_bytes); btrfs_set_stack_chunk_owner(chunk, extent_root->root_key.objectid); btrfs_set_stack_chunk_stripe_len(chunk, stripe_len); btrfs_set_stack_chunk_type(chunk, type); btrfs_set_stack_chunk_num_stripes(chunk, num_stripes); btrfs_set_stack_chunk_io_align(chunk, stripe_len); btrfs_set_stack_chunk_io_width(chunk, stripe_len); btrfs_set_stack_chunk_sector_size(chunk, extent_root->sectorsize); btrfs_set_stack_chunk_sub_stripes(chunk, sub_stripes); map->sector_size = extent_root->sectorsize; map->stripe_len = stripe_len; map->io_align = stripe_len; map->io_width = stripe_len; map->type = type; map->num_stripes = num_stripes; map->sub_stripes = sub_stripes; ret = btrfs_insert_item(trans, chunk_root, &key, chunk, btrfs_chunk_item_size(num_stripes)); BUG_ON(ret); *start = key.offset;; map->ce.start = key.offset; map->ce.size = *num_bytes; ret = insert_cache_extent(&info->mapping_tree.cache_tree, &map->ce); BUG_ON(ret); if (type & BTRFS_BLOCK_GROUP_SYSTEM) { ret = btrfs_add_system_chunk(trans, chunk_root, &key, chunk, btrfs_chunk_item_size(num_stripes)); BUG_ON(ret); } kfree(chunk); return ret; } int btrfs_alloc_data_chunk(struct btrfs_trans_handle *trans, struct btrfs_root *extent_root, u64 *start, u64 num_bytes, u64 type) { u64 dev_offset; struct btrfs_fs_info *info = extent_root->fs_info; struct btrfs_root *chunk_root = info->chunk_root; struct btrfs_stripe *stripes; struct btrfs_device *device = NULL; struct btrfs_chunk *chunk; struct list_head *dev_list = &info->fs_devices->devices; struct list_head *cur; struct map_lookup *map; u64 calc_size = 8 * 1024 * 1024; int num_stripes = 1; int sub_stripes = 0; int ret; int index; int stripe_len = BTRFS_STRIPE_LEN; struct btrfs_key key; key.objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID; key.type = BTRFS_CHUNK_ITEM_KEY; ret = find_next_chunk(chunk_root, BTRFS_FIRST_CHUNK_TREE_OBJECTID, &key.offset); if (ret) return ret; chunk = kmalloc(btrfs_chunk_item_size(num_stripes), GFP_NOFS); if (!chunk) return -ENOMEM; map = kmalloc(btrfs_map_lookup_size(num_stripes), GFP_NOFS); if (!map) { kfree(chunk); return -ENOMEM; } stripes = &chunk->stripe; calc_size = num_bytes; index = 0; cur = dev_list->next; device = list_entry(cur, struct btrfs_device, dev_list); while (index < num_stripes) { struct btrfs_stripe *stripe; ret = btrfs_alloc_dev_extent(trans, device, info->chunk_root->root_key.objectid, BTRFS_FIRST_CHUNK_TREE_OBJECTID, key.offset, calc_size, &dev_offset); BUG_ON(ret); device->bytes_used += calc_size; ret = btrfs_update_device(trans, device); BUG_ON(ret); map->stripes[index].dev = device; map->stripes[index].physical = dev_offset; stripe = stripes + index; btrfs_set_stack_stripe_devid(stripe, device->devid); btrfs_set_stack_stripe_offset(stripe, dev_offset); memcpy(stripe->dev_uuid, device->uuid, BTRFS_UUID_SIZE); index++; } /* key was set above */ btrfs_set_stack_chunk_length(chunk, num_bytes); btrfs_set_stack_chunk_owner(chunk, extent_root->root_key.objectid); btrfs_set_stack_chunk_stripe_len(chunk, stripe_len); btrfs_set_stack_chunk_type(chunk, type); btrfs_set_stack_chunk_num_stripes(chunk, num_stripes); btrfs_set_stack_chunk_io_align(chunk, stripe_len); btrfs_set_stack_chunk_io_width(chunk, stripe_len); btrfs_set_stack_chunk_sector_size(chunk, extent_root->sectorsize); btrfs_set_stack_chunk_sub_stripes(chunk, sub_stripes); map->sector_size = extent_root->sectorsize; map->stripe_len = stripe_len; map->io_align = stripe_len; map->io_width = stripe_len; map->type = type; map->num_stripes = num_stripes; map->sub_stripes = sub_stripes; ret = btrfs_insert_item(trans, chunk_root, &key, chunk, btrfs_chunk_item_size(num_stripes)); BUG_ON(ret); *start = key.offset; map->ce.start = key.offset; map->ce.size = num_bytes; ret = insert_cache_extent(&info->mapping_tree.cache_tree, &map->ce); BUG_ON(ret); kfree(chunk); return ret; } int btrfs_num_copies(struct btrfs_mapping_tree *map_tree, u64 logical, u64 len) { struct cache_extent *ce; struct map_lookup *map; int ret; ce = search_cache_extent(&map_tree->cache_tree, logical); if (!ce) { fprintf(stderr, "No mapping for %llu-%llu\n", (unsigned long long)logical, (unsigned long long)logical+len); return 1; } if (ce->start > logical || ce->start + ce->size < logical) { fprintf(stderr, "Invalid mapping for %llu-%llu, got " "%llu-%llu\n", (unsigned long long)logical, (unsigned long long)logical+len, (unsigned long long)ce->start, (unsigned long long)ce->start + ce->size); return 1; } map = container_of(ce, struct map_lookup, ce); if (map->type & (BTRFS_BLOCK_GROUP_DUP | BTRFS_BLOCK_GROUP_RAID1)) ret = map->num_stripes; else if (map->type & BTRFS_BLOCK_GROUP_RAID10) ret = map->sub_stripes; else if (map->type & BTRFS_BLOCK_GROUP_RAID5) ret = 2; else if (map->type & BTRFS_BLOCK_GROUP_RAID6) ret = 3; else ret = 1; return ret; } int btrfs_next_metadata(struct btrfs_mapping_tree *map_tree, u64 *logical, u64 *size) { struct cache_extent *ce; struct map_lookup *map; ce = search_cache_extent(&map_tree->cache_tree, *logical); while (ce) { ce = next_cache_extent(ce); if (!ce) return -ENOENT; map = container_of(ce, struct map_lookup, ce); if (map->type & BTRFS_BLOCK_GROUP_METADATA) { *logical = ce->start; *size = ce->size; return 0; } } return -ENOENT; } int btrfs_rmap_block(struct btrfs_mapping_tree *map_tree, u64 chunk_start, u64 physical, u64 devid, u64 **logical, int *naddrs, int *stripe_len) { struct cache_extent *ce; struct map_lookup *map; u64 *buf; u64 bytenr; u64 length; u64 stripe_nr; u64 rmap_len; int i, j, nr = 0; ce = search_cache_extent(&map_tree->cache_tree, chunk_start); BUG_ON(!ce); map = container_of(ce, struct map_lookup, ce); length = ce->size; rmap_len = map->stripe_len; if (map->type & BTRFS_BLOCK_GROUP_RAID10) length = ce->size / (map->num_stripes / map->sub_stripes); else if (map->type & BTRFS_BLOCK_GROUP_RAID0) length = ce->size / map->num_stripes; else if (map->type & (BTRFS_BLOCK_GROUP_RAID5 | BTRFS_BLOCK_GROUP_RAID6)) { length = ce->size / nr_data_stripes(map); rmap_len = map->stripe_len * nr_data_stripes(map); } buf = kzalloc(sizeof(u64) * map->num_stripes, GFP_NOFS); for (i = 0; i < map->num_stripes; i++) { if (devid && map->stripes[i].dev->devid != devid) continue; if (map->stripes[i].physical > physical || map->stripes[i].physical + length <= physical) continue; stripe_nr = (physical - map->stripes[i].physical) / map->stripe_len; if (map->type & BTRFS_BLOCK_GROUP_RAID10) { stripe_nr = (stripe_nr * map->num_stripes + i) / map->sub_stripes; } else if (map->type & BTRFS_BLOCK_GROUP_RAID0) { stripe_nr = stripe_nr * map->num_stripes + i; } /* else if RAID[56], multiply by nr_data_stripes(). * Alternatively, just use rmap_len below instead of * map->stripe_len */ bytenr = ce->start + stripe_nr * rmap_len; for (j = 0; j < nr; j++) { if (buf[j] == bytenr) break; } if (j == nr) buf[nr++] = bytenr; } *logical = buf; *naddrs = nr; *stripe_len = rmap_len; return 0; } static inline int parity_smaller(u64 a, u64 b) { return a > b; } /* Bubble-sort the stripe set to put the parity/syndrome stripes last */ static void sort_parity_stripes(struct btrfs_multi_bio *bbio, u64 *raid_map) { struct btrfs_bio_stripe s; int i; u64 l; int again = 1; while (again) { again = 0; for (i = 0; i < bbio->num_stripes - 1; i++) { if (parity_smaller(raid_map[i], raid_map[i+1])) { s = bbio->stripes[i]; l = raid_map[i]; bbio->stripes[i] = bbio->stripes[i+1]; raid_map[i] = raid_map[i+1]; bbio->stripes[i+1] = s; raid_map[i+1] = l; again = 1; } } } } int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, u64 logical, u64 *length, struct btrfs_multi_bio **multi_ret, int mirror_num, u64 **raid_map_ret) { return __btrfs_map_block(map_tree, rw, logical, length, NULL, multi_ret, mirror_num, raid_map_ret); } int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, u64 logical, u64 *length, u64 *type, struct btrfs_multi_bio **multi_ret, int mirror_num, u64 **raid_map_ret) { struct cache_extent *ce; struct map_lookup *map; u64 offset; u64 stripe_offset; u64 stripe_nr; u64 *raid_map = NULL; int stripes_allocated = 8; int stripes_required = 1; int stripe_index; int i; struct btrfs_multi_bio *multi = NULL; if (multi_ret && rw == READ) { stripes_allocated = 1; } again: ce = search_cache_extent(&map_tree->cache_tree, logical); if (!ce) { kfree(multi); return -ENOENT; } if (ce->start > logical || ce->start + ce->size < logical) { kfree(multi); return -ENOENT; } if (multi_ret) { multi = kzalloc(btrfs_multi_bio_size(stripes_allocated), GFP_NOFS); if (!multi) return -ENOMEM; } map = container_of(ce, struct map_lookup, ce); offset = logical - ce->start; if (rw == WRITE) { if (map->type & (BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_DUP)) { stripes_required = map->num_stripes; } else if (map->type & BTRFS_BLOCK_GROUP_RAID10) { stripes_required = map->sub_stripes; } } if (map->type & (BTRFS_BLOCK_GROUP_RAID5 | BTRFS_BLOCK_GROUP_RAID6) && multi_ret && ((rw & WRITE) || mirror_num > 1) && raid_map_ret) { /* RAID[56] write or recovery. Return all stripes */ stripes_required = map->num_stripes; /* Only allocate the map if we've already got a large enough multi_ret */ if (stripes_allocated >= stripes_required) { raid_map = kmalloc(sizeof(u64) * map->num_stripes, GFP_NOFS); if (!raid_map) { kfree(multi); return -ENOMEM; } } } /* if our multi bio struct is too small, back off and try again */ if (multi_ret && stripes_allocated < stripes_required) { stripes_allocated = stripes_required; kfree(multi); multi = NULL; goto again; } stripe_nr = offset; /* * stripe_nr counts the total number of stripes we have to stride * to get to this block */ stripe_nr = stripe_nr / map->stripe_len; stripe_offset = stripe_nr * map->stripe_len; BUG_ON(offset < stripe_offset); /* stripe_offset is the offset of this block in its stripe*/ stripe_offset = offset - stripe_offset; if (map->type & (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID5 | BTRFS_BLOCK_GROUP_RAID6 | BTRFS_BLOCK_GROUP_RAID10 | BTRFS_BLOCK_GROUP_DUP)) { /* we limit the length of each bio to what fits in a stripe */ *length = min_t(u64, ce->size - offset, map->stripe_len - stripe_offset); } else { *length = ce->size - offset; } if (!multi_ret) goto out; multi->num_stripes = 1; stripe_index = 0; if (map->type & BTRFS_BLOCK_GROUP_RAID1) { if (rw == WRITE) multi->num_stripes = map->num_stripes; else if (mirror_num) stripe_index = mirror_num - 1; else stripe_index = stripe_nr % map->num_stripes; } else if (map->type & BTRFS_BLOCK_GROUP_RAID10) { int factor = map->num_stripes / map->sub_stripes; stripe_index = stripe_nr % factor; stripe_index *= map->sub_stripes; if (rw == WRITE) multi->num_stripes = map->sub_stripes; else if (mirror_num) stripe_index += mirror_num - 1; stripe_nr = stripe_nr / factor; } else if (map->type & BTRFS_BLOCK_GROUP_DUP) { if (rw == WRITE) multi->num_stripes = map->num_stripes; else if (mirror_num) stripe_index = mirror_num - 1; } else if (map->type & (BTRFS_BLOCK_GROUP_RAID5 | BTRFS_BLOCK_GROUP_RAID6)) { if (raid_map) { int rot; u64 tmp; u64 raid56_full_stripe_start; u64 full_stripe_len = nr_data_stripes(map) * map->stripe_len; /* * align the start of our data stripe in the logical * address space */ raid56_full_stripe_start = offset / full_stripe_len; raid56_full_stripe_start *= full_stripe_len; /* get the data stripe number */ stripe_nr = raid56_full_stripe_start / map->stripe_len; stripe_nr = stripe_nr / nr_data_stripes(map); /* Work out the disk rotation on this stripe-set */ rot = stripe_nr % map->num_stripes; /* Fill in the logical address of each stripe */ tmp = stripe_nr * nr_data_stripes(map); for (i = 0; i < nr_data_stripes(map); i++) raid_map[(i+rot) % map->num_stripes] = ce->start + (tmp + i) * map->stripe_len; raid_map[(i+rot) % map->num_stripes] = BTRFS_RAID5_P_STRIPE; if (map->type & BTRFS_BLOCK_GROUP_RAID6) raid_map[(i+rot+1) % map->num_stripes] = BTRFS_RAID6_Q_STRIPE; *length = map->stripe_len; stripe_index = 0; stripe_offset = 0; multi->num_stripes = map->num_stripes; } else { stripe_index = stripe_nr % nr_data_stripes(map); stripe_nr = stripe_nr / nr_data_stripes(map); /* * Mirror #0 or #1 means the original data block. * Mirror #2 is RAID5 parity block. * Mirror #3 is RAID6 Q block. */ if (mirror_num > 1) stripe_index = nr_data_stripes(map) + mirror_num - 2; /* We distribute the parity blocks across stripes */ stripe_index = (stripe_nr + stripe_index) % map->num_stripes; } } else { /* * after this do_div call, stripe_nr is the number of stripes * on this device we have to walk to find the data, and * stripe_index is the number of our device in the stripe array */ stripe_index = stripe_nr % map->num_stripes; stripe_nr = stripe_nr / map->num_stripes; } BUG_ON(stripe_index >= map->num_stripes); for (i = 0; i < multi->num_stripes; i++) { multi->stripes[i].physical = map->stripes[stripe_index].physical + stripe_offset + stripe_nr * map->stripe_len; multi->stripes[i].dev = map->stripes[stripe_index].dev; stripe_index++; } *multi_ret = multi; if (type) *type = map->type; if (raid_map) { sort_parity_stripes(multi, raid_map); *raid_map_ret = raid_map; } out: return 0; } struct btrfs_device *btrfs_find_device(struct btrfs_root *root, u64 devid, u8 *uuid, u8 *fsid) { struct btrfs_device *device; struct btrfs_fs_devices *cur_devices; cur_devices = root->fs_info->fs_devices; while (cur_devices) { if (!fsid || !memcmp(cur_devices->fsid, fsid, BTRFS_UUID_SIZE)) { device = __find_device(&cur_devices->devices, devid, uuid); if (device) return device; } cur_devices = cur_devices->seed; } return NULL; } struct btrfs_device * btrfs_find_device_by_devid(struct btrfs_fs_devices *fs_devices, u64 devid, int instance) { struct list_head *head = &fs_devices->devices; struct btrfs_device *dev; int num_found = 0; list_for_each_entry(dev, head, dev_list) { if (dev->devid == devid && num_found++ == instance) return dev; } return NULL; } int btrfs_chunk_readonly(struct btrfs_root *root, u64 chunk_offset) { struct cache_extent *ce; struct map_lookup *map; struct btrfs_mapping_tree *map_tree = &root->fs_info->mapping_tree; int readonly = 0; int i; /* * During chunk recovering, we may fail to find block group's * corresponding chunk, we will rebuild it later */ ce = search_cache_extent(&map_tree->cache_tree, chunk_offset); if (!root->fs_info->is_chunk_recover) BUG_ON(!ce); else return 0; map = container_of(ce, struct map_lookup, ce); for (i = 0; i < map->num_stripes; i++) { if (!map->stripes[i].dev->writeable) { readonly = 1; break; } } return readonly; } static struct btrfs_device *fill_missing_device(u64 devid) { struct btrfs_device *device; device = kzalloc(sizeof(*device), GFP_NOFS); device->devid = devid; device->fd = -1; return device; } static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key, struct extent_buffer *leaf, struct btrfs_chunk *chunk) { struct btrfs_mapping_tree *map_tree = &root->fs_info->mapping_tree; struct map_lookup *map; struct cache_extent *ce; u64 logical; u64 length; u64 devid; u8 uuid[BTRFS_UUID_SIZE]; int num_stripes; int ret; int i; logical = key->offset; length = btrfs_chunk_length(leaf, chunk); ce = search_cache_extent(&map_tree->cache_tree, logical); /* already mapped? */ if (ce && ce->start <= logical && ce->start + ce->size > logical) { return 0; } num_stripes = btrfs_chunk_num_stripes(leaf, chunk); map = kmalloc(btrfs_map_lookup_size(num_stripes), GFP_NOFS); if (!map) return -ENOMEM; map->ce.start = logical; map->ce.size = length; map->num_stripes = num_stripes; map->io_width = btrfs_chunk_io_width(leaf, chunk); map->io_align = btrfs_chunk_io_align(leaf, chunk); map->sector_size = btrfs_chunk_sector_size(leaf, chunk); map->stripe_len = btrfs_chunk_stripe_len(leaf, chunk); map->type = btrfs_chunk_type(leaf, chunk); map->sub_stripes = btrfs_chunk_sub_stripes(leaf, chunk); for (i = 0; i < num_stripes; i++) { map->stripes[i].physical = btrfs_stripe_offset_nr(leaf, chunk, i); devid = btrfs_stripe_devid_nr(leaf, chunk, i); read_extent_buffer(leaf, uuid, (unsigned long) btrfs_stripe_dev_uuid_nr(chunk, i), BTRFS_UUID_SIZE); map->stripes[i].dev = btrfs_find_device(root, devid, uuid, NULL); if (!map->stripes[i].dev) { map->stripes[i].dev = fill_missing_device(devid); printf("warning, device %llu is missing\n", (unsigned long long)devid); } } ret = insert_cache_extent(&map_tree->cache_tree, &map->ce); BUG_ON(ret); return 0; } static int fill_device_from_item(struct extent_buffer *leaf, struct btrfs_dev_item *dev_item, struct btrfs_device *device) { unsigned long ptr; device->devid = btrfs_device_id(leaf, dev_item); device->total_bytes = btrfs_device_total_bytes(leaf, dev_item); device->bytes_used = btrfs_device_bytes_used(leaf, dev_item); device->type = btrfs_device_type(leaf, dev_item); device->io_align = btrfs_device_io_align(leaf, dev_item); device->io_width = btrfs_device_io_width(leaf, dev_item); device->sector_size = btrfs_device_sector_size(leaf, dev_item); ptr = (unsigned long)btrfs_device_uuid(dev_item); read_extent_buffer(leaf, device->uuid, ptr, BTRFS_UUID_SIZE); return 0; } static int open_seed_devices(struct btrfs_root *root, u8 *fsid) { struct btrfs_fs_devices *fs_devices; int ret; fs_devices = root->fs_info->fs_devices->seed; while (fs_devices) { if (!memcmp(fs_devices->fsid, fsid, BTRFS_UUID_SIZE)) { ret = 0; goto out; } fs_devices = fs_devices->seed; } fs_devices = find_fsid(fsid); if (!fs_devices) { /* missing all seed devices */ fs_devices = kzalloc(sizeof(*fs_devices), GFP_NOFS); if (!fs_devices) { ret = -ENOMEM; goto out; } INIT_LIST_HEAD(&fs_devices->devices); list_add(&fs_devices->list, &fs_uuids); memcpy(fs_devices->fsid, fsid, BTRFS_FSID_SIZE); } ret = btrfs_open_devices(fs_devices, O_RDONLY); if (ret) goto out; fs_devices->seed = root->fs_info->fs_devices->seed; root->fs_info->fs_devices->seed = fs_devices; out: return ret; } static int read_one_dev(struct btrfs_root *root, struct extent_buffer *leaf, struct btrfs_dev_item *dev_item) { struct btrfs_device *device; u64 devid; int ret = 0; u8 fs_uuid[BTRFS_UUID_SIZE]; u8 dev_uuid[BTRFS_UUID_SIZE]; devid = btrfs_device_id(leaf, dev_item); read_extent_buffer(leaf, dev_uuid, (unsigned long)btrfs_device_uuid(dev_item), BTRFS_UUID_SIZE); read_extent_buffer(leaf, fs_uuid, (unsigned long)btrfs_device_fsid(dev_item), BTRFS_UUID_SIZE); if (memcmp(fs_uuid, root->fs_info->fsid, BTRFS_UUID_SIZE)) { ret = open_seed_devices(root, fs_uuid); if (ret) return ret; } device = btrfs_find_device(root, devid, dev_uuid, fs_uuid); if (!device) { printk("warning devid %llu not found already\n", (unsigned long long)devid); device = kzalloc(sizeof(*device), GFP_NOFS); if (!device) return -ENOMEM; device->fd = -1; list_add(&device->dev_list, &root->fs_info->fs_devices->devices); } fill_device_from_item(leaf, dev_item, device); device->dev_root = root->fs_info->dev_root; return ret; } int btrfs_read_sys_array(struct btrfs_root *root) { struct btrfs_super_block *super_copy = root->fs_info->super_copy; struct extent_buffer *sb; struct btrfs_disk_key *disk_key; struct btrfs_chunk *chunk; struct btrfs_key key; u32 num_stripes; u32 len = 0; u8 *ptr; u8 *array_end; int ret = 0; sb = btrfs_find_create_tree_block(root, BTRFS_SUPER_INFO_OFFSET, BTRFS_SUPER_INFO_SIZE); if (!sb) return -ENOMEM; btrfs_set_buffer_uptodate(sb); write_extent_buffer(sb, super_copy, 0, sizeof(*super_copy)); array_end = ((u8 *)super_copy->sys_chunk_array) + btrfs_super_sys_array_size(super_copy); /* * we do this loop twice, once for the device items and * once for all of the chunks. This way there are device * structs filled in for every chunk */ ptr = super_copy->sys_chunk_array; while (ptr < array_end) { disk_key = (struct btrfs_disk_key *)ptr; btrfs_disk_key_to_cpu(&key, disk_key); len = sizeof(*disk_key); ptr += len; if (key.type == BTRFS_CHUNK_ITEM_KEY) { chunk = (struct btrfs_chunk *)(ptr - (u8 *)super_copy); ret = read_one_chunk(root, &key, sb, chunk); if (ret) break; num_stripes = btrfs_chunk_num_stripes(sb, chunk); len = btrfs_chunk_item_size(num_stripes); } else { BUG(); } ptr += len; } free_extent_buffer(sb); return ret; } int btrfs_read_chunk_tree(struct btrfs_root *root) { struct btrfs_path *path; struct extent_buffer *leaf; struct btrfs_key key; struct btrfs_key found_key; int ret; int slot; root = root->fs_info->chunk_root; path = btrfs_alloc_path(); if (!path) return -ENOMEM; /* * Read all device items, and then all the chunk items. All * device items are found before any chunk item (their object id * is smaller than the lowest possible object id for a chunk * item - BTRFS_FIRST_CHUNK_TREE_OBJECTID). */ key.objectid = BTRFS_DEV_ITEMS_OBJECTID; key.offset = 0; key.type = 0; ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); if (ret < 0) goto error; while(1) { leaf = path->nodes[0]; slot = path->slots[0]; if (slot >= btrfs_header_nritems(leaf)) { ret = btrfs_next_leaf(root, path); if (ret == 0) continue; if (ret < 0) goto error; break; } btrfs_item_key_to_cpu(leaf, &found_key, slot); if (found_key.type == BTRFS_DEV_ITEM_KEY) { struct btrfs_dev_item *dev_item; dev_item = btrfs_item_ptr(leaf, slot, struct btrfs_dev_item); ret = read_one_dev(root, leaf, dev_item); BUG_ON(ret); } else if (found_key.type == BTRFS_CHUNK_ITEM_KEY) { struct btrfs_chunk *chunk; chunk = btrfs_item_ptr(leaf, slot, struct btrfs_chunk); ret = read_one_chunk(root, &found_key, leaf, chunk); BUG_ON(ret); } path->slots[0]++; } ret = 0; error: btrfs_free_path(path); return ret; } struct list_head *btrfs_scanned_uuids(void) { return &fs_uuids; } static int rmw_eb(struct btrfs_fs_info *info, struct extent_buffer *eb, struct extent_buffer *orig_eb) { int ret; unsigned long orig_off = 0; unsigned long dest_off = 0; unsigned long copy_len = eb->len; ret = read_whole_eb(info, eb, 0); if (ret) return ret; if (eb->start + eb->len <= orig_eb->start || eb->start >= orig_eb->start + orig_eb->len) return 0; /* * | ----- orig_eb ------- | * | ----- stripe ------- | * | ----- orig_eb ------- | * | ----- orig_eb ------- | */ if (eb->start > orig_eb->start) orig_off = eb->start - orig_eb->start; if (orig_eb->start > eb->start) dest_off = orig_eb->start - eb->start; if (copy_len > orig_eb->len - orig_off) copy_len = orig_eb->len - orig_off; if (copy_len > eb->len - dest_off) copy_len = eb->len - dest_off; memcpy(eb->data + dest_off, orig_eb->data + orig_off, copy_len); return 0; } static void split_eb_for_raid56(struct btrfs_fs_info *info, struct extent_buffer *orig_eb, struct extent_buffer **ebs, u64 stripe_len, u64 *raid_map, int num_stripes) { struct extent_buffer *eb; u64 start = orig_eb->start; u64 this_eb_start; int i; int ret; for (i = 0; i < num_stripes; i++) { if (raid_map[i] >= BTRFS_RAID5_P_STRIPE) break; eb = malloc(sizeof(struct extent_buffer) + stripe_len); if (!eb) BUG(); memset(eb, 0, sizeof(struct extent_buffer) + stripe_len); eb->start = raid_map[i]; eb->len = stripe_len; eb->refs = 1; eb->flags = 0; eb->fd = -1; eb->dev_bytenr = (u64)-1; this_eb_start = raid_map[i]; if (start > this_eb_start || start + orig_eb->len < this_eb_start + stripe_len) { ret = rmw_eb(info, eb, orig_eb); BUG_ON(ret); } else { memcpy(eb->data, orig_eb->data + eb->start - start, stripe_len); } ebs[i] = eb; } } int write_raid56_with_parity(struct btrfs_fs_info *info, struct extent_buffer *eb, struct btrfs_multi_bio *multi, u64 stripe_len, u64 *raid_map) { struct extent_buffer **ebs, *p_eb = NULL, *q_eb = NULL; int i; int j; int ret; int alloc_size = eb->len; ebs = kmalloc(sizeof(*ebs) * multi->num_stripes, GFP_NOFS); BUG_ON(!ebs); if (stripe_len > alloc_size) alloc_size = stripe_len; split_eb_for_raid56(info, eb, ebs, stripe_len, raid_map, multi->num_stripes); for (i = 0; i < multi->num_stripes; i++) { struct extent_buffer *new_eb; if (raid_map[i] < BTRFS_RAID5_P_STRIPE) { ebs[i]->dev_bytenr = multi->stripes[i].physical; ebs[i]->fd = multi->stripes[i].dev->fd; multi->stripes[i].dev->total_ios++; BUG_ON(ebs[i]->start != raid_map[i]); continue; } new_eb = kmalloc(sizeof(*eb) + alloc_size, GFP_NOFS); BUG_ON(!new_eb); new_eb->dev_bytenr = multi->stripes[i].physical; new_eb->fd = multi->stripes[i].dev->fd; multi->stripes[i].dev->total_ios++; new_eb->len = stripe_len; if (raid_map[i] == BTRFS_RAID5_P_STRIPE) p_eb = new_eb; else if (raid_map[i] == BTRFS_RAID6_Q_STRIPE) q_eb = new_eb; } if (q_eb) { void **pointers; pointers = kmalloc(sizeof(*pointers) * multi->num_stripes, GFP_NOFS); BUG_ON(!pointers); ebs[multi->num_stripes - 2] = p_eb; ebs[multi->num_stripes - 1] = q_eb; for (i = 0; i < multi->num_stripes; i++) pointers[i] = ebs[i]->data; raid6_gen_syndrome(multi->num_stripes, stripe_len, pointers); kfree(pointers); } else { ebs[multi->num_stripes - 1] = p_eb; memcpy(p_eb->data, ebs[0]->data, stripe_len); for (j = 1; j < multi->num_stripes - 1; j++) { for (i = 0; i < stripe_len; i += sizeof(unsigned long)) { *(unsigned long *)(p_eb->data + i) ^= *(unsigned long *)(ebs[j]->data + i); } } } for (i = 0; i < multi->num_stripes; i++) { ret = write_extent_to_disk(ebs[i]); BUG_ON(ret); if (ebs[i] != eb) kfree(ebs[i]); } kfree(ebs); return 0; } partclone-0.2.86/src/btrfs/volumes.h000066400000000000000000000135341262102574200173570ustar00rootroot00000000000000/* * Copyright (C) 2007 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. */ #ifndef __BTRFS_VOLUMES_ #define __BTRFS_VOLUMES_ #define BTRFS_STRIPE_LEN (64 * 1024) struct btrfs_device { struct list_head dev_list; struct btrfs_root *dev_root; struct btrfs_fs_devices *fs_devices; u64 total_ios; int fd; int writeable; char *name; /* these are read off the super block, only in the progs */ char *label; u64 total_devs; u64 super_bytes_used; u64 generation; /* the internal btrfs device id */ u64 devid; /* size of the device */ u64 total_bytes; /* bytes used */ u64 bytes_used; /* optimal io alignment for this device */ u32 io_align; /* optimal io width for this device */ u32 io_width; /* minimal io size for this device */ u32 sector_size; /* type and info about this device */ u64 type; /* physical drive uuid (or lvm uuid) */ u8 uuid[BTRFS_UUID_SIZE]; }; struct btrfs_fs_devices { u8 fsid[BTRFS_FSID_SIZE]; /* FS specific uuid */ /* the device with this id has the most recent copy of the super */ u64 latest_devid; u64 latest_trans; u64 lowest_devid; int latest_bdev; int lowest_bdev; struct list_head devices; struct list_head list; int seeding; struct btrfs_fs_devices *seed; }; struct btrfs_bio_stripe { struct btrfs_device *dev; u64 physical; }; struct btrfs_multi_bio { int error; int num_stripes; struct btrfs_bio_stripe stripes[]; }; struct map_lookup { struct cache_extent ce; u64 type; int io_align; int io_width; int stripe_len; int sector_size; int num_stripes; int sub_stripes; struct btrfs_bio_stripe stripes[]; }; #define btrfs_multi_bio_size(n) (sizeof(struct btrfs_multi_bio) + \ (sizeof(struct btrfs_bio_stripe) * (n))) #define btrfs_map_lookup_size(n) (sizeof(struct map_lookup) + \ (sizeof(struct btrfs_bio_stripe) * (n))) /* * Restriper's general type filter */ #define BTRFS_BALANCE_DATA (1ULL << 0) #define BTRFS_BALANCE_SYSTEM (1ULL << 1) #define BTRFS_BALANCE_METADATA (1ULL << 2) #define BTRFS_BALANCE_TYPE_MASK (BTRFS_BALANCE_DATA | \ BTRFS_BALANCE_SYSTEM | \ BTRFS_BALANCE_METADATA) #define BTRFS_BALANCE_FORCE (1ULL << 3) #define BTRFS_BALANCE_RESUME (1ULL << 4) /* * Balance filters */ #define BTRFS_BALANCE_ARGS_PROFILES (1ULL << 0) #define BTRFS_BALANCE_ARGS_USAGE (1ULL << 1) #define BTRFS_BALANCE_ARGS_DEVID (1ULL << 2) #define BTRFS_BALANCE_ARGS_DRANGE (1ULL << 3) #define BTRFS_BALANCE_ARGS_VRANGE (1ULL << 4) #define BTRFS_BALANCE_ARGS_LIMIT (1ULL << 5) /* * Profile changing flags. When SOFT is set we won't relocate chunk if * it already has the target profile (even though it may be * half-filled). */ #define BTRFS_BALANCE_ARGS_CONVERT (1ULL << 8) #define BTRFS_BALANCE_ARGS_SOFT (1ULL << 9) #define BTRFS_RAID5_P_STRIPE ((u64)-2) #define BTRFS_RAID6_Q_STRIPE ((u64)-1) int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, u64 logical, u64 *length, u64 *type, struct btrfs_multi_bio **multi_ret, int mirror_num, u64 **raid_map); int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, u64 logical, u64 *length, struct btrfs_multi_bio **multi_ret, int mirror_num, u64 **raid_map_ret); int btrfs_next_metadata(struct btrfs_mapping_tree *map_tree, u64 *logical, u64 *size); int btrfs_rmap_block(struct btrfs_mapping_tree *map_tree, u64 chunk_start, u64 physical, u64 devid, u64 **logical, int *naddrs, int *stripe_len); int btrfs_read_sys_array(struct btrfs_root *root); int btrfs_read_chunk_tree(struct btrfs_root *root); int btrfs_alloc_chunk(struct btrfs_trans_handle *trans, struct btrfs_root *extent_root, u64 *start, u64 *num_bytes, u64 type); int btrfs_alloc_data_chunk(struct btrfs_trans_handle *trans, struct btrfs_root *extent_root, u64 *start, u64 num_bytes, u64 type); int btrfs_read_super_device(struct btrfs_root *root, struct extent_buffer *buf); int btrfs_add_device(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_device *device); int btrfs_open_devices(struct btrfs_fs_devices *fs_devices, int flags); int btrfs_close_devices(struct btrfs_fs_devices *fs_devices); int btrfs_add_device(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_device *device); int btrfs_update_device(struct btrfs_trans_handle *trans, struct btrfs_device *device); int btrfs_scan_one_device(int fd, const char *path, struct btrfs_fs_devices **fs_devices_ret, u64 *total_devs, u64 super_offset, int super_recover); int btrfs_num_copies(struct btrfs_mapping_tree *map_tree, u64 logical, u64 len); struct list_head *btrfs_scanned_uuids(void); int btrfs_add_system_chunk(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_key *key, struct btrfs_chunk *chunk, int item_size); int btrfs_chunk_readonly(struct btrfs_root *root, u64 chunk_offset); struct btrfs_device * btrfs_find_device_by_devid(struct btrfs_fs_devices *fs_devices, u64 devid, int instance); struct btrfs_device *btrfs_find_device(struct btrfs_root *root, u64 devid, u8 *uuid, u8 *fsid); int write_raid56_with_parity(struct btrfs_fs_info *info, struct extent_buffer *eb, struct btrfs_multi_bio *multi, u64 stripe_len, u64 *raid_map); #endif partclone-0.2.86/src/btrfsclone.c000066400000000000000000000303631262102574200167000ustar00rootroot00000000000000/** * btrfsclone.c - part of Partclone project * * Copyright (c) 2007~ Thomas Tsai * * read btrfs super block and extent * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ #define _XOPEN_SOURCE 500 #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include "btrfs/ctree.h" #include "btrfs/volumes.h" #include "btrfs/disk-io.h" #include "btrfs/utils.h" #include "btrfs/version.h" #include "partclone.h" #include "btrfsclone.h" #include "progress.h" #include "fs_common.h" char *EXECNAME = "partclone.btrfs"; extern fs_cmd_opt fs_opt; struct btrfs_fs_info *info; struct btrfs_root *root; struct btrfs_path path; int block_size = 0; uint64_t dev_size = 0; ///set useb block static void set_bitmap(unsigned long* bitmap, uint64_t pos, uint64_t length){ uint64_t block; uint64_t pos_block; uint64_t block_end; log_mesg(3, 0, 0, fs_opt.debug, "%s: offset: %llu size: %llu block_size: %i\n", __FILE__, pos, length, block_size); if (pos > dev_size) { log_mesg(1, 0, 0, fs_opt.debug, "%s: offset(%llu) larger than device size(%llu), skip it.\n", __FILE__, pos, dev_size); return; } pos_block = pos/block_size; block_end = (pos+length)/block_size; if ((pos+length)%block_size > 0) block_end++; log_mesg(3, 0, 0, fs_opt.debug, "%s: block offset: %llu block count: %llu\n",__FILE__, pos_block, block_end); for(block = pos_block; block < block_end; block++){ log_mesg(3, 0, 0, fs_opt.debug, "%s: block %i is used\n",__FILE__, block); pc_set_bit(block, bitmap); } } int check_extent_bitmap(unsigned long* bitmap, u64 bytenr, u64 *num_bytes) { struct btrfs_multi_bio *multi = NULL; int ret = 0; int mirror = 0; //struct btrfs_fs_info *info = root->fs_info; u64 maxlen = *num_bytes; if (*num_bytes % root->sectorsize) return -EINVAL; ret = btrfs_map_block(&info->mapping_tree, READ, bytenr, num_bytes, &multi, mirror, NULL); if (ret) { log_mesg(1, 0, 0, fs_opt.debug, "%s: Couldn't map the block %llu\n", __FILE__, bytenr); } log_mesg(3, 0, 0, fs_opt.debug, "%s: read data from %llu and size %llu\n", __FILE__, multi->stripes[0].physical, *num_bytes); if (*num_bytes > maxlen) *num_bytes = maxlen; set_bitmap(bitmap, multi->stripes[0].physical, *num_bytes); return 0; } static void dump_file_extent_item(unsigned long* bitmap, struct extent_buffer *eb, struct btrfs_item *item, int slot, struct btrfs_file_extent_item *fi) { int extent_type = btrfs_file_extent_type(eb, fi); if (extent_type == BTRFS_FILE_EXTENT_INLINE) { return; } if (extent_type == BTRFS_FILE_EXTENT_PREALLOC) { log_mesg(3, 0, 0, fs_opt.debug, "%s: DUMP: prealloc data disk byte %llu nr %llu\n", __FILE__, (unsigned long long)btrfs_file_extent_disk_bytenr(eb, fi), (unsigned long long)btrfs_file_extent_disk_num_bytes(eb, fi)); set_bitmap(bitmap, (unsigned long long)btrfs_file_extent_disk_bytenr(eb, fi), (unsigned long long)btrfs_file_extent_disk_num_bytes(eb, fi) ); return; } log_mesg(3, 0, 0, fs_opt.debug, "DUMP: extent data disk byte %llu nr %llu\n", (unsigned long long)btrfs_file_extent_disk_bytenr(eb, fi), (unsigned long long)btrfs_file_extent_disk_num_bytes(eb, fi)); set_bitmap(bitmap, (unsigned long long)btrfs_file_extent_disk_bytenr(eb, fi), (unsigned long long)btrfs_file_extent_disk_num_bytes(eb, fi) ); } int csum_bitmap(unsigned long* bitmap, struct btrfs_root *root){ struct extent_buffer *leaf; struct btrfs_key key; u64 offset = 0, num_bytes = 0; u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy); int ret = 0; u64 data_len; unsigned long leaf_offset; log_mesg(2, 0, 0, fs_opt.debug, "%s: csum_bitmap\n", __FILE__); root = root->fs_info->csum_root; key.objectid = BTRFS_EXTENT_CSUM_OBJECTID; key.type = BTRFS_EXTENT_CSUM_KEY; key.offset = 0; btrfs_init_path(&path); ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0); if (ret < 0) { log_mesg(0, 0, 1, fs_opt.debug, "%s: Error searching csum tree %d\n", __FILE__, ret); btrfs_free_path(&path); return ret; } if (ret > 0 && path.slots[0]) path.slots[0]--; ret = 0; while (1) { if (path.slots[0] >= btrfs_header_nritems(path.nodes[0])) { ret = btrfs_next_leaf(root, &path); if (ret < 0) { log_mesg(0, 0, 1, fs_opt.debug, "%s: Error going to next leaf %d\n", __FILE__, ret); break; } if (ret) break; } leaf = path.nodes[0]; btrfs_item_key_to_cpu(leaf, &key, path.slots[0]); if (key.type != BTRFS_EXTENT_CSUM_KEY) { path.slots[0]++; continue; } data_len = (btrfs_item_size_nr(leaf, path.slots[0]) / csum_size) * root->sectorsize; leaf_offset = btrfs_item_ptr_offset(leaf, path.slots[0]); log_mesg(2, 0, 0, fs_opt.debug, "%s: leaf_offset %lu\n", __FILE__, leaf_offset); ret = check_extent_bitmap(bitmap, key.offset, &data_len); if (ret) break; if (!num_bytes) { offset = key.offset; } else if (key.offset != offset + num_bytes) { offset = key.offset; num_bytes = 0; } num_bytes += data_len; path.slots[0]++; } btrfs_release_path(&path); return ret; } void dump_start_leaf(unsigned long* bitmap, struct btrfs_root *root, struct extent_buffer *eb){ u64 bytenr; u64 size; u64 objectid; u32 type; int i; struct btrfs_item *item; struct btrfs_disk_key disk_key; struct btrfs_file_extent_item *fi; u32 leaf_size; if (!eb) return; if (btrfs_is_leaf(eb)) { size = btrfs_level_size(root, btrfs_root_level(&root->root_item)); log_mesg(3, 0, 0, fs_opt.debug, "%s: DUMP: leaf %llu\n", __FILE__, (unsigned long long)btrfs_header_bytenr(eb)); bytenr = (unsigned long long)btrfs_header_bytenr(eb); check_extent_bitmap(bitmap, bytenr, &size); u32 nr = btrfs_header_nritems(eb); for (i = 0 ; i < nr ; i++) { item = btrfs_item_nr(i); btrfs_item_key(eb, &disk_key, i); type = btrfs_disk_key_type(&disk_key); if (type == BTRFS_EXTENT_DATA_KEY){ fi = btrfs_item_ptr(eb, i, struct btrfs_file_extent_item); dump_file_extent_item(bitmap, eb, item, i, fi); } if (type == BTRFS_EXTENT_ITEM_KEY){ objectid = btrfs_disk_key_objectid(&disk_key); check_extent_bitmap(bitmap, objectid, &size); } } return; } u32 nr = btrfs_header_nritems(eb); leaf_size = btrfs_level_size(root, btrfs_header_level(eb) - 1); for (i = 0; i < nr; i++) { struct extent_buffer *next = read_tree_block(root, btrfs_node_blockptr(eb, i), leaf_size, btrfs_node_ptr_generation(eb, i)); if (!next) { log_mesg(0, 0, 1, fs_opt.debug, "%s: failed to read %llu in tree %llu\n", __FILE__, (unsigned long long)btrfs_node_blockptr(eb, i), (unsigned long long)btrfs_header_owner(eb)); continue; } if (btrfs_is_leaf(next) && btrfs_header_level(eb) != 1) log_mesg(0, 0, 1, fs_opt.debug, "%s(%i): BUG\n", __FILE__, __LINE__); if (btrfs_header_level(next) != btrfs_header_level(eb) - 1) log_mesg(0, 0, 1, fs_opt.debug, "%s(%i): BUG\n", __FILE__, __LINE__); dump_start_leaf(bitmap, root, next); free_extent_buffer(next); } } /// open device static void fs_open(char* device){ struct cache_tree root_cache; //struct btrfs_fs_info *info; u64 bytenr = 0; enum btrfs_open_ctree_flags ctree_flags = OPEN_CTREE_PARTIAL; log_mesg(0, 0, 0, fs_opt.debug, "\n%s: btrfs library version = %s\n", __FILE__, BTRFS_BUILD_VERSION); radix_tree_init(); cache_tree_init(&root_cache); info = open_ctree_fs_info(device, bytenr, 0, ctree_flags); if (!info) { log_mesg(0, 1, 1, fs_opt.debug, "%s: Couldn't open file system\n", __FILE__); } root = info->fs_root; if (!extent_buffer_uptodate(info->tree_root->node) || !extent_buffer_uptodate(info->dev_root->node) || !extent_buffer_uptodate(info->chunk_root->node)) { log_mesg(0, 1, 1, fs_opt.debug, "%s: Critical roots corrupted, unable to fsck the FS\n", __FILE__); } if(!root){ log_mesg(0, 1, 1, fs_opt.debug, "%s: Unable to open %s\n", __FILE__, device); } } /// close device static void fs_close(){ close_ctree(root); } /// readbitmap - read bitmap extern void readbitmap(char* device, image_head image_hdr, unsigned long* bitmap, int pui) { int ret; struct btrfs_root *tree_root_scan; struct btrfs_key key; struct btrfs_disk_key disk_key; struct btrfs_key found_key; struct extent_buffer *leaf; struct btrfs_root_item ri; int slot; fs_open(device); dev_size = image_hdr.device_size; block_size = btrfs_super_nodesize(info->super_copy); set_bitmap(bitmap, BTRFS_SUPER_INFO_OFFSET, block_size); //check_extent_bitmap(bitmap, btrfs_root_bytenr(&info->extent_root->root_item), &block_size); //check_extent_bitmap(bitmap, btrfs_root_bytenr(&info->csum_root->root_item), &block_size); //check_extent_bitmap(bitmap, btrfs_root_bytenr(&info->quota_root->root_item), &block_size); //check_extent_bitmap(bitmap, btrfs_root_bytenr(&info->dev_root->root_item), &block_size); //check_extent_bitmap(bitmap, btrfs_root_bytenr(&info->tree_root->root_item), &block_size); //check_extent_bitmap(bitmap, btrfs_root_bytenr(&info->chunk_root->root_item), &block_size); //check_extent_bitmap(bitmap, btrfs_root_bytenr(&info->fs_root->root_item), &block_size); //log_mesg(3, 0, 0, fs_opt.debug, "%s: super tree done.\n", __FILE__); if (info->tree_root->node) { log_mesg(3, 0, 0, fs_opt.debug, "%s: root tree:\n", __FILE__); dump_start_leaf(bitmap, info->tree_root, info->tree_root->node); } if (info->chunk_root->node) { log_mesg(3, 0, 0, fs_opt.debug, "%s: chunk tree:\n", __FILE__); dump_start_leaf(bitmap, info->chunk_root, info->chunk_root->node); } tree_root_scan = info->tree_root; btrfs_init_path(&path); if (!extent_buffer_uptodate(tree_root_scan->node)) goto no_node; key.offset = 0; key.objectid = 0; btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY); ret = btrfs_search_slot(NULL, tree_root_scan, &key, &path, 0, 0); while(1) { leaf = path.nodes[0]; slot = path.slots[0]; if (slot >= btrfs_header_nritems(leaf)) { ret = btrfs_next_leaf(tree_root_scan, &path); if (ret != 0) break; leaf = path.nodes[0]; slot = path.slots[0]; } btrfs_item_key(leaf, &disk_key, path.slots[0]); btrfs_disk_key_to_cpu(&found_key, &disk_key); if (btrfs_key_type(&found_key) == BTRFS_ROOT_ITEM_KEY) { unsigned long offset; struct extent_buffer *buf; offset = btrfs_item_ptr_offset(leaf, slot); read_extent_buffer(leaf, &ri, offset, sizeof(ri)); buf = read_tree_block(tree_root_scan, btrfs_root_bytenr(&ri), btrfs_level_size(tree_root_scan, btrfs_root_level(&ri)), 0); if (!extent_buffer_uptodate(buf)) goto next; dump_start_leaf(bitmap, tree_root_scan, buf); free_extent_buffer(buf); } next: path.slots[0]++; } no_node: csum_bitmap(bitmap, root); btrfs_release_path(&path); } /// read super block and write to image head extern void initial_image_hdr(char* device, image_head* image_hdr) { fs_open(device); strncpy(image_hdr->magic, IMAGE_MAGIC, IMAGE_MAGIC_SIZE); strncpy(image_hdr->fs, btrfs_MAGIC, FS_MAGIC_SIZE); image_hdr->block_size = btrfs_super_nodesize(info->super_copy); log_mesg(0, 0, 0, fs_opt.debug, "%s: block_size = %i\n", __FILE__, image_hdr->block_size); image_hdr->usedblocks = (btrfs_super_bytes_used(info->super_copy)/image_hdr->block_size); log_mesg(0, 0, 0, fs_opt.debug, "%s: usedblock = %lli\n", __FILE__, image_hdr->usedblocks); image_hdr->device_size = btrfs_super_total_bytes(info->super_copy); log_mesg(0, 0, 0, fs_opt.debug, "%s: device_size = %llu\n", __FILE__, image_hdr->device_size); image_hdr->totalblock = (uint64_t)(image_hdr->device_size/image_hdr->block_size); log_mesg(0, 0, 0, fs_opt.debug, "%s: totalblock = %lli\n", __FILE__, image_hdr->totalblock); fs_close(); log_mesg(0, 0, 0, fs_opt.debug, "%s: fs_close\n", __FILE__); } partclone-0.2.86/src/btrfsclone.h000066400000000000000000000012061262102574200166770ustar00rootroot00000000000000/** * btrfsclone.h - part of Partclone project * * Copyright (c) 2007~ Thomas Tsai * * read btrfe super block and extent * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ /// readbitmap - read bitmap extern void readbitmap(char* device, image_head image_hdr, unsigned long* bitmap, int pui); /// read super block and write to image head extern void initial_image_hdr(char* device, image_head* image_hdr); partclone-0.2.86/src/ddclone.c000066400000000000000000000025011262102574200161400ustar00rootroot00000000000000/** * ddclone.c - part of Partclone project * * Copyright (c) 2007~ Thomas Tsai * Copyright (c) 2013~ Raman Shishnew * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ #include #include #include "partclone.h" extern cmd_opt opt; /// readbitmap - read bitmap extern void readbitmap(char* device, image_head image_hdr, unsigned long* bitmap, int pui) { /// initial image bitmap as 1 (all block are used) memset(bitmap, 0xFF, sizeof(unsigned long)*LONGS(image_hdr.totalblock)); } /// read super block and write to image head extern void initial_image_hdr(char* device, image_head* image_hdr) { int src; if ((src = open_source(device, &opt)) == -1) { log_mesg(0, 1, 1, opt.debug, "Error exit\n"); } strncpy(image_hdr->magic, IMAGE_MAGIC, IMAGE_MAGIC_SIZE); strncpy(image_hdr->fs, raw_MAGIC, FS_MAGIC_SIZE); image_hdr->block_size = PART_SECTOR_SIZE; image_hdr->device_size = get_partition_size(&src); image_hdr->totalblock = image_hdr->device_size / PART_SECTOR_SIZE; image_hdr->usedblocks = image_hdr->device_size / PART_SECTOR_SIZE; close(src); } partclone-0.2.86/src/ddclone.h000066400000000000000000000011331262102574200161450ustar00rootroot00000000000000/** * ddclone.h - part of Partclone project * * Copyright (c) 2013~ Raman Shishnew * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ /// readbitmap - read bitmap extern void readbitmap(char* device, image_head image_hdr, unsigned long* bitmap, int pui); /// read super block and write to image head extern void initial_image_hdr(char* device, image_head* image_hdr); partclone-0.2.86/src/deplib_version.c000066400000000000000000000037101262102574200175370ustar00rootroot00000000000000#include #include #ifdef EXTFS #include #elif REISERFS #include #elif REISER4 #include #elif XFS #elif HFSPLUS #elif FAT #elif NTFS #include #elif VMFS #include #elif BTRFS #include "btrfs/version.h" #endif int main(int argc, char **argv){ char *libfs; int err=0; if(argv[1]){ libfs = argv[1]; } else { libfs="xxx"; } //printf("%s\n", libfs); if (strcmp(libfs, "ntfs") == 0){ err = libntfs_version(); } else if (strcmp(libfs, "extfs") == 0) { err = libextfs_version(); } else if (strcmp(libfs, "reiserfs") == 0) { err = libreiserfs_version(); } else if (strcmp(libfs, "vmfs") == 0) { err = libvmfs_version(); } else if (strcmp(libfs, "reiser4") == 0) { err = libpreiser4_version(); } else if (strcmp(libfs, "btrfs") == 0) { err = libbtrfs_version(); } if(err == 1){ printf("0\n"); } return 0; } int libvmfs_version(){ #ifdef VMFS char *version; version = "0.2.0"; #ifdef VMFS5_ZLA_BASE version = "0.2.5"; #endif printf("%s\n", version); #endif } int libntfs_version(){ #ifdef NTFS printf("%s\n", ntfs_libntfs_version()); return 0; #endif return 1; } int libextfs_version(){ #ifdef EXTFS const char *lib_ver; ext2fs_get_library_version(&lib_ver, 0); printf("%s\n", lib_ver); return 0; #endif return 1; } int libpreiser4_version(){ #ifdef REISER4 const char *lib_ver; lib_ver = (const char *)libreiser4_version(); printf("%s\n", lib_ver); return 0; #endif return 1; } int libreiserfs_version(){ #ifdef REISERFS const char *lib_ver; lib_ver = (const char *)libreiserfs_get_version(); printf("%s\n", lib_ver); return 0; #endif return 1; } int libbtrfs_version(){ #ifdef BTRFS printf("%s\n", BTRFS_BUILD_VERSION); return 0; #endif return 1; } partclone-0.2.86/src/exfat/000077500000000000000000000000001262102574200154755ustar00rootroot00000000000000partclone-0.2.86/src/exfat/byteorder.h000066400000000000000000000043251262102574200176510ustar00rootroot00000000000000/* byteorder.h (12.01.10) Endianness stuff. exFAT uses little-endian byte order. Free exFAT implementation. Copyright (C) 2010-2014 Andrew Nayenko This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef BYTEORDER_H_INCLUDED #define BYTEORDER_H_INCLUDED #include #include "platform.h" typedef struct { uint16_t __u16; } le16_t; typedef struct { uint32_t __u32; } le32_t; typedef struct { uint64_t __u64; } le64_t; #if EXFAT_BYTE_ORDER == EXFAT_LITTLE_ENDIAN static inline uint16_t le16_to_cpu(le16_t v) { return v.__u16; } static inline uint32_t le32_to_cpu(le32_t v) { return v.__u32; } static inline uint64_t le64_to_cpu(le64_t v) { return v.__u64; } static inline le16_t cpu_to_le16(uint16_t v) { le16_t t = {v}; return t; } static inline le32_t cpu_to_le32(uint32_t v) { le32_t t = {v}; return t; } static inline le64_t cpu_to_le64(uint64_t v) { le64_t t = {v}; return t; } typedef size_t bitmap_t; #elif EXFAT_BYTE_ORDER == EXFAT_BIG_ENDIAN static inline uint16_t le16_to_cpu(le16_t v) { return exfat_bswap16(v.__u16); } static inline uint32_t le32_to_cpu(le32_t v) { return exfat_bswap32(v.__u32); } static inline uint64_t le64_to_cpu(le64_t v) { return exfat_bswap64(v.__u64); } static inline le16_t cpu_to_le16(uint16_t v) { le16_t t = {exfat_bswap16(v)}; return t; } static inline le32_t cpu_to_le32(uint32_t v) { le32_t t = {exfat_bswap32(v)}; return t; } static inline le64_t cpu_to_le64(uint64_t v) { le64_t t = {exfat_bswap64(v)}; return t; } typedef unsigned char bitmap_t; #else #error Wow! You have a PDP machine?! #endif #endif /* ifndef BYTEORDER_H_INCLUDED */ partclone-0.2.86/src/exfat/cluster.c000066400000000000000000000277771262102574200173460ustar00rootroot00000000000000/* cluster.c (03.09.09) exFAT file system implementation library. Free exFAT implementation. Copyright (C) 2010-2014 Andrew Nayenko This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "exfat.h" #include #include #include /* * Sector to absolute offset. */ static off_t s2o(const struct exfat* ef, off_t sector) { return sector << ef->sb->sector_bits; } /* * Cluster to sector. */ static off_t c2s(const struct exfat* ef, cluster_t cluster) { if (cluster < EXFAT_FIRST_DATA_CLUSTER) exfat_bug("invalid cluster number %u", cluster); return le32_to_cpu(ef->sb->cluster_sector_start) + ((off_t) (cluster - EXFAT_FIRST_DATA_CLUSTER) << ef->sb->spc_bits); } /* * Cluster to absolute offset. */ off_t exfat_c2o(const struct exfat* ef, cluster_t cluster) { return s2o(ef, c2s(ef, cluster)); } /* * Sector to cluster. */ static cluster_t s2c(const struct exfat* ef, off_t sector) { return ((sector - le32_to_cpu(ef->sb->cluster_sector_start)) >> ef->sb->spc_bits) + EXFAT_FIRST_DATA_CLUSTER; } /* * Size in bytes to size in clusters (rounded upwards). */ static uint32_t bytes2clusters(const struct exfat* ef, uint64_t bytes) { uint64_t cluster_size = CLUSTER_SIZE(*ef->sb); return (bytes + cluster_size - 1) / cluster_size; } cluster_t exfat_next_cluster(const struct exfat* ef, const struct exfat_node* node, cluster_t cluster) { le32_t next; off_t fat_offset; if (cluster < EXFAT_FIRST_DATA_CLUSTER) exfat_bug("bad cluster 0x%x", cluster); if (IS_CONTIGUOUS(*node)) return cluster + 1; fat_offset = s2o(ef, le32_to_cpu(ef->sb->fat_sector_start)) + cluster * sizeof(cluster_t); if (exfat_pread(ef->dev, &next, sizeof(next), fat_offset) < 0) return EXFAT_CLUSTER_BAD; /* the caller should handle this and print appropriate error message */ return le32_to_cpu(next); } cluster_t exfat_advance_cluster(const struct exfat* ef, struct exfat_node* node, uint32_t count) { uint32_t i; if (node->fptr_index > count) { node->fptr_index = 0; node->fptr_cluster = node->start_cluster; } for (i = node->fptr_index; i < count; i++) { node->fptr_cluster = exfat_next_cluster(ef, node, node->fptr_cluster); if (CLUSTER_INVALID(node->fptr_cluster)) break; /* the caller should handle this and print appropriate error message */ } node->fptr_index = count; return node->fptr_cluster; } static cluster_t find_bit_and_set(bitmap_t* bitmap, size_t start, size_t end) { const size_t start_index = start / sizeof(bitmap_t) / 8; const size_t end_index = DIV_ROUND_UP(end, sizeof(bitmap_t) * 8); size_t i; size_t start_bitindex; size_t end_bitindex; size_t c; for (i = start_index; i < end_index; i++) { if (bitmap[i] == ~((bitmap_t) 0)) continue; start_bitindex = MAX(i * sizeof(bitmap_t) * 8, start); end_bitindex = MIN((i + 1) * sizeof(bitmap_t) * 8, end); for (c = start_bitindex; c < end_bitindex; c++) if (BMAP_GET(bitmap, c) == 0) { BMAP_SET(bitmap, c); return c + EXFAT_FIRST_DATA_CLUSTER; } } return EXFAT_CLUSTER_END; } static int flush_nodes(struct exfat* ef, struct exfat_node* node) { struct exfat_node* p; for (p = node->child; p != NULL; p = p->next) { int rc = flush_nodes(ef, p); if (rc != 0) return rc; } return exfat_flush_node(ef, node); } int exfat_flush(struct exfat* ef) { int rc = flush_nodes(ef, ef->root); if (ef->cmap.dirty) { if (exfat_pwrite(ef->dev, ef->cmap.chunk, BMAP_SIZE(ef->cmap.chunk_size), exfat_c2o(ef, ef->cmap.start_cluster)) < 0) { exfat_error("failed to write clusters bitmap"); return -EIO; } ef->cmap.dirty = false; } return rc; } static bool set_next_cluster(const struct exfat* ef, bool contiguous, cluster_t current, cluster_t next) { off_t fat_offset; le32_t next_le32; if (contiguous) return true; fat_offset = s2o(ef, le32_to_cpu(ef->sb->fat_sector_start)) + current * sizeof(cluster_t); next_le32 = cpu_to_le32(next); if (exfat_pwrite(ef->dev, &next_le32, sizeof(next_le32), fat_offset) < 0) { exfat_error("failed to write the next cluster %#x after %#x", next, current); return false; } return true; } static cluster_t allocate_cluster(struct exfat* ef, cluster_t hint) { cluster_t cluster; hint -= EXFAT_FIRST_DATA_CLUSTER; if (hint >= ef->cmap.chunk_size) hint = 0; cluster = find_bit_and_set(ef->cmap.chunk, hint, ef->cmap.chunk_size); if (cluster == EXFAT_CLUSTER_END) cluster = find_bit_and_set(ef->cmap.chunk, 0, hint); if (cluster == EXFAT_CLUSTER_END) { exfat_error("no free space left"); return EXFAT_CLUSTER_END; } ef->cmap.dirty = true; return cluster; } static void free_cluster(struct exfat* ef, cluster_t cluster) { if (CLUSTER_INVALID(cluster)) exfat_bug("freeing invalid cluster 0x%x", cluster); if (cluster - EXFAT_FIRST_DATA_CLUSTER >= ef->cmap.size) exfat_bug("freeing non-existing cluster 0x%x (0x%x)", cluster, ef->cmap.size); BMAP_CLR(ef->cmap.chunk, cluster - EXFAT_FIRST_DATA_CLUSTER); ef->cmap.dirty = true; } static bool make_noncontiguous(const struct exfat* ef, cluster_t first, cluster_t last) { cluster_t c; for (c = first; c < last; c++) if (!set_next_cluster(ef, false, c, c + 1)) return false; return true; } static int shrink_file(struct exfat* ef, struct exfat_node* node, uint32_t current, uint32_t difference); static int grow_file(struct exfat* ef, struct exfat_node* node, uint32_t current, uint32_t difference) { cluster_t previous; cluster_t next; uint32_t allocated = 0; if (difference == 0) exfat_bug("zero clusters count passed"); if (node->start_cluster != EXFAT_CLUSTER_FREE) { /* get the last cluster of the file */ previous = exfat_advance_cluster(ef, node, current - 1); if (CLUSTER_INVALID(previous)) { exfat_error("invalid cluster 0x%x while growing", previous); return -EIO; } } else { if (node->fptr_index != 0) exfat_bug("non-zero pointer index (%u)", node->fptr_index); /* file does not have clusters (i.e. is empty), allocate the first one for it */ previous = allocate_cluster(ef, 0); if (CLUSTER_INVALID(previous)) return -ENOSPC; node->fptr_cluster = node->start_cluster = previous; allocated = 1; /* file consists of only one cluster, so it's contiguous */ node->flags |= EXFAT_ATTRIB_CONTIGUOUS; } while (allocated < difference) { next = allocate_cluster(ef, previous + 1); if (CLUSTER_INVALID(next)) { if (allocated != 0) shrink_file(ef, node, current + allocated, allocated); return -ENOSPC; } if (next != previous - 1 && IS_CONTIGUOUS(*node)) { /* it's a pity, but we are not able to keep the file contiguous anymore */ if (!make_noncontiguous(ef, node->start_cluster, previous)) return -EIO; node->flags &= ~EXFAT_ATTRIB_CONTIGUOUS; node->flags |= EXFAT_ATTRIB_DIRTY; } if (!set_next_cluster(ef, IS_CONTIGUOUS(*node), previous, next)) return -EIO; previous = next; allocated++; } if (!set_next_cluster(ef, IS_CONTIGUOUS(*node), previous, EXFAT_CLUSTER_END)) return -EIO; return 0; } static int shrink_file(struct exfat* ef, struct exfat_node* node, uint32_t current, uint32_t difference) { cluster_t previous; cluster_t next; if (difference == 0) exfat_bug("zero difference passed"); if (node->start_cluster == EXFAT_CLUSTER_FREE) exfat_bug("unable to shrink empty file (%u clusters)", current); if (current < difference) exfat_bug("file underflow (%u < %u)", current, difference); /* crop the file */ if (current > difference) { cluster_t last = exfat_advance_cluster(ef, node, current - difference - 1); if (CLUSTER_INVALID(last)) { exfat_error("invalid cluster 0x%x while shrinking", last); return -EIO; } previous = exfat_next_cluster(ef, node, last); if (!set_next_cluster(ef, IS_CONTIGUOUS(*node), last, EXFAT_CLUSTER_END)) return -EIO; } else { previous = node->start_cluster; node->start_cluster = EXFAT_CLUSTER_FREE; node->flags |= EXFAT_ATTRIB_DIRTY; } node->fptr_index = 0; node->fptr_cluster = node->start_cluster; /* free remaining clusters */ while (difference--) { if (CLUSTER_INVALID(previous)) { exfat_error("invalid cluster 0x%x while freeing after shrink", previous); return -EIO; } next = exfat_next_cluster(ef, node, previous); if (!set_next_cluster(ef, IS_CONTIGUOUS(*node), previous, EXFAT_CLUSTER_FREE)) return -EIO; free_cluster(ef, previous); previous = next; } return 0; } static bool erase_raw(struct exfat* ef, size_t size, off_t offset) { if (exfat_pwrite(ef->dev, ef->zero_cluster, size, offset) < 0) { exfat_error("failed to erase %zu bytes at %"PRId64, size, offset); return false; } return true; } static int erase_range(struct exfat* ef, struct exfat_node* node, uint64_t begin, uint64_t end) { uint64_t cluster_boundary; cluster_t cluster; if (begin >= end) return 0; cluster_boundary = (begin | (CLUSTER_SIZE(*ef->sb) - 1)) + 1; cluster = exfat_advance_cluster(ef, node, begin / CLUSTER_SIZE(*ef->sb)); if (CLUSTER_INVALID(cluster)) { exfat_error("invalid cluster 0x%x while erasing", cluster); return -EIO; } /* erase from the beginning to the closest cluster boundary */ if (!erase_raw(ef, MIN(cluster_boundary, end) - begin, exfat_c2o(ef, cluster) + begin % CLUSTER_SIZE(*ef->sb))) return -EIO; /* erase whole clusters */ while (cluster_boundary < end) { cluster = exfat_next_cluster(ef, node, cluster); /* the cluster cannot be invalid because we have just allocated it */ if (CLUSTER_INVALID(cluster)) exfat_bug("invalid cluster 0x%x after allocation", cluster); if (!erase_raw(ef, CLUSTER_SIZE(*ef->sb), exfat_c2o(ef, cluster))) return -EIO; cluster_boundary += CLUSTER_SIZE(*ef->sb); } return 0; } int exfat_truncate(struct exfat* ef, struct exfat_node* node, uint64_t size, bool erase) { uint32_t c1 = bytes2clusters(ef, node->size); uint32_t c2 = bytes2clusters(ef, size); int rc = 0; if (node->references == 0 && node->parent) exfat_bug("no references, node changes can be lost"); if (node->size == size) return 0; if (c1 < c2) rc = grow_file(ef, node, c1, c2 - c1); else if (c1 > c2) rc = shrink_file(ef, node, c1, c1 - c2); if (rc != 0) return rc; if (erase) { rc = erase_range(ef, node, node->size, size); if (rc != 0) return rc; } exfat_update_mtime(node); node->size = size; node->flags |= EXFAT_ATTRIB_DIRTY; return 0; } uint32_t exfat_count_free_clusters(const struct exfat* ef) { uint32_t free_clusters = 0; uint32_t i; for (i = 0; i < ef->cmap.size; i++) if (BMAP_GET(ef->cmap.chunk, i) == 0) free_clusters++; return free_clusters; } static int find_used_clusters(const struct exfat* ef, cluster_t* a, cluster_t* b) { const cluster_t end = le32_to_cpu(ef->sb->cluster_count); /* find first used cluster */ for (*a = *b + 1; *a < end; (*a)++) if (BMAP_GET(ef->cmap.chunk, *a - EXFAT_FIRST_DATA_CLUSTER)) break; if (*a >= end) return 1; /* find last contiguous used cluster */ for (*b = *a; *b < end; (*b)++) if (BMAP_GET(ef->cmap.chunk, *b - EXFAT_FIRST_DATA_CLUSTER) == 0) { (*b)--; break; } return 0; } int exfat_find_used_sectors(const struct exfat* ef, off_t* a, off_t* b) { cluster_t ca, cb; if (*a == 0 && *b == 0) ca = cb = EXFAT_FIRST_DATA_CLUSTER - 1; else { ca = s2c(ef, *a); cb = s2c(ef, *b); } if (find_used_clusters(ef, &ca, &cb) != 0) return 1; if (*a != 0 || *b != 0) *a = c2s(ef, ca); *b = c2s(ef, cb) + (CLUSTER_SIZE(*ef->sb) - 1) / SECTOR_SIZE(*ef->sb); return 0; } partclone-0.2.86/src/exfat/compiler.h000066400000000000000000000035161262102574200174650ustar00rootroot00000000000000/* compiler.h (09.06.13) Compiler-specific definitions. Note that unknown compiler is not a showstopper. Free exFAT implementation. Copyright (C) 2010-2014 Andrew Nayenko This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef COMPILER_H_INCLUDED #define COMPILER_H_INCLUDED #if __STDC_VERSION__ < 199901L #error C99-compliant compiler is required #endif #if defined(__clang__) #define PRINTF __attribute__((format(printf, 1, 2))) #define NORETURN __attribute__((noreturn)) #define PACKED __attribute__((packed)) #if __has_extension(c_static_assert) #define USE_C11_STATIC_ASSERT #endif #elif defined(__GNUC__) #define PRINTF __attribute__((format(printf, 1, 2))) #define NORETURN __attribute__((noreturn)) #define PACKED __attribute__((packed)) #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) #define USE_C11_STATIC_ASSERT #endif #else #define PRINTF #define NORETURN #define PACKED #endif #ifdef USE_C11_STATIC_ASSERT #define STATIC_ASSERT(cond) _Static_assert(cond, #cond) #else #define CONCAT2(a, b) a ## b #define CONCAT1(a, b) CONCAT2(a, b) #define STATIC_ASSERT(cond) \ extern void CONCAT1(static_assert, __LINE__)(int x[(cond) ? 1 : -1]) #endif #endif /* ifndef COMPILER_H_INCLUDED */ partclone-0.2.86/src/exfat/exfat.h000066400000000000000000000171331262102574200167620ustar00rootroot00000000000000/* exfat.h (29.08.09) Definitions of structures and constants used in exFAT file system implementation. Free exFAT implementation. Copyright (C) 2010-2014 Andrew Nayenko This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef EXFAT_H_INCLUDED #define EXFAT_H_INCLUDED #include #include #include #include #include #include #include "compiler.h" #include "exfatfs.h" #include "version.h" #define EXFAT_NAME_MAX 256 #define EXFAT_ATTRIB_CONTIGUOUS 0x10000 #define EXFAT_ATTRIB_CACHED 0x20000 #define EXFAT_ATTRIB_DIRTY 0x40000 #define EXFAT_ATTRIB_UNLINKED 0x80000 #define IS_CONTIGUOUS(node) (((node).flags & EXFAT_ATTRIB_CONTIGUOUS) != 0) #define SECTOR_SIZE(sb) (1 << (sb).sector_bits) #define CLUSTER_SIZE(sb) (SECTOR_SIZE(sb) << (sb).spc_bits) #define CLUSTER_INVALID(c) \ ((c) < EXFAT_FIRST_DATA_CLUSTER || (c) > EXFAT_LAST_DATA_CLUSTER) #define MIN(a, b) ((a) < (b) ? (a) : (b)) #define MAX(a, b) ((a) > (b) ? (a) : (b)) #define DIV_ROUND_UP(x, d) (((x) + (d) - 1) / (d)) #define ROUND_UP(x, d) (DIV_ROUND_UP(x, d) * (d)) #define UTF8_BYTES(c) ((c) * 6) /* UTF-8 character can occupy up to 6 bytes */ #define BMAP_SIZE(count) (ROUND_UP(count, sizeof(bitmap_t) * 8) / 8) #define BMAP_BLOCK(index) ((index) / sizeof(bitmap_t) / 8) #define BMAP_MASK(index) ((bitmap_t) 1 << ((index) % (sizeof(bitmap_t) * 8))) #define BMAP_GET(bitmap, index) \ ((bitmap)[BMAP_BLOCK(index)] & BMAP_MASK(index)) #define BMAP_SET(bitmap, index) \ ((bitmap)[BMAP_BLOCK(index)] |= BMAP_MASK(index)) #define BMAP_CLR(bitmap, index) \ ((bitmap)[BMAP_BLOCK(index)] &= ~BMAP_MASK(index)) struct exfat_node { struct exfat_node* parent; struct exfat_node* child; struct exfat_node* next; struct exfat_node* prev; int references; uint32_t fptr_index; cluster_t fptr_cluster; cluster_t entry_cluster; off_t entry_offset; cluster_t start_cluster; int flags; uint64_t size; time_t mtime, atime; le16_t name[EXFAT_NAME_MAX + 1]; }; enum exfat_mode { EXFAT_MODE_RO, EXFAT_MODE_RW, EXFAT_MODE_ANY, }; struct exfat_dev; struct exfat { struct exfat_dev* dev; struct exfat_super_block* sb; le16_t* upcase; size_t upcase_chars; struct exfat_node* root; struct { cluster_t start_cluster; uint32_t size; /* in bits */ bitmap_t* chunk; uint32_t chunk_size; /* in bits */ bool dirty; } cmap; char label[UTF8_BYTES(EXFAT_ENAME_MAX) + 1]; void* zero_cluster; int dmask, fmask; uid_t uid; gid_t gid; int ro; bool noatime; }; /* in-core nodes iterator */ struct exfat_iterator { struct exfat_node* parent; struct exfat_node* current; }; struct exfat_human_bytes { uint64_t value; const char* unit; }; extern int exfat_errors; void exfat_bug(const char* format, ...) PRINTF NORETURN; void exfat_error(const char* format, ...) PRINTF; void exfat_warn(const char* format, ...) PRINTF; void exfat_debug(const char* format, ...) PRINTF; struct exfat_dev* exfat_open(const char* spec, enum exfat_mode mode); int exfat_close(struct exfat_dev* dev); int exfat_fsync(struct exfat_dev* dev); enum exfat_mode exfat_get_mode(const struct exfat_dev* dev); off_t exfat_get_size(const struct exfat_dev* dev); off_t exfat_seek(struct exfat_dev* dev, off_t offset, int whence); ssize_t exfat_read(struct exfat_dev* dev, void* buffer, size_t size); ssize_t exfat_write(struct exfat_dev* dev, const void* buffer, size_t size); ssize_t exfat_pread(struct exfat_dev* dev, void* buffer, size_t size, off_t offset); ssize_t exfat_pwrite(struct exfat_dev* dev, const void* buffer, size_t size, off_t offset); ssize_t exfat_generic_pread(const struct exfat* ef, struct exfat_node* node, void* buffer, size_t size, off_t offset); ssize_t exfat_generic_pwrite(struct exfat* ef, struct exfat_node* node, const void* buffer, size_t size, off_t offset); int exfat_opendir(struct exfat* ef, struct exfat_node* dir, struct exfat_iterator* it); void exfat_closedir(struct exfat* ef, struct exfat_iterator* it); struct exfat_node* exfat_readdir(struct exfat* ef, struct exfat_iterator* it); int exfat_lookup(struct exfat* ef, struct exfat_node** node, const char* path); int exfat_split(struct exfat* ef, struct exfat_node** parent, struct exfat_node** node, le16_t* name, const char* path); off_t exfat_c2o(const struct exfat* ef, cluster_t cluster); cluster_t exfat_next_cluster(const struct exfat* ef, const struct exfat_node* node, cluster_t cluster); cluster_t exfat_advance_cluster(const struct exfat* ef, struct exfat_node* node, uint32_t count); int exfat_flush(struct exfat* ef); int exfat_truncate(struct exfat* ef, struct exfat_node* node, uint64_t size, bool erase); uint32_t exfat_count_free_clusters(const struct exfat* ef); int exfat_find_used_sectors(const struct exfat* ef, off_t* a, off_t* b); void exfat_stat(const struct exfat* ef, const struct exfat_node* node, struct stat* stbuf); void exfat_get_name(const struct exfat_node* node, char* buffer, size_t n); uint16_t exfat_start_checksum(const struct exfat_entry_meta1* entry); uint16_t exfat_add_checksum(const void* entry, uint16_t sum); le16_t exfat_calc_checksum(const struct exfat_entry_meta1* meta1, const struct exfat_entry_meta2* meta2, const le16_t* name); uint32_t exfat_vbr_start_checksum(const void* sector, size_t size); uint32_t exfat_vbr_add_checksum(const void* sector, size_t size, uint32_t sum); le16_t exfat_calc_name_hash(const struct exfat* ef, const le16_t* name); void exfat_humanize_bytes(uint64_t value, struct exfat_human_bytes* hb); void exfat_print_info(const struct exfat_super_block* sb, uint32_t free_clusters); int utf16_to_utf8(char* output, const le16_t* input, size_t outsize, size_t insize); int utf8_to_utf16(le16_t* output, const char* input, size_t outsize, size_t insize); size_t utf16_length(const le16_t* str); struct exfat_node* exfat_get_node(struct exfat_node* node); void exfat_put_node(struct exfat* ef, struct exfat_node* node); int exfat_cleanup_node(struct exfat* ef, struct exfat_node* node); int exfat_cache_directory(struct exfat* ef, struct exfat_node* dir); void exfat_reset_cache(struct exfat* ef); int exfat_flush_node(struct exfat* ef, struct exfat_node* node); int exfat_unlink(struct exfat* ef, struct exfat_node* node); int exfat_rmdir(struct exfat* ef, struct exfat_node* node); int exfat_mknod(struct exfat* ef, const char* path); int exfat_mkdir(struct exfat* ef, const char* path); int exfat_rename(struct exfat* ef, const char* old_path, const char* new_path); void exfat_utimes(struct exfat_node* node, const struct timespec tv[2]); void exfat_update_atime(struct exfat_node* node); void exfat_update_mtime(struct exfat_node* node); const char* exfat_get_label(struct exfat* ef); int exfat_set_label(struct exfat* ef, const char* label); int exfat_mount(struct exfat* ef, const char* spec, const char* options); void exfat_unmount(struct exfat* ef); time_t exfat_exfat2unix(le16_t date, le16_t time, uint8_t centisec); void exfat_unix2exfat(time_t unix_time, le16_t* date, le16_t* time, uint8_t* centisec); void exfat_tzset(void); #endif /* ifndef EXFAT_H_INCLUDED */ partclone-0.2.86/src/exfat/exfatfs.h000066400000000000000000000130401262102574200173040ustar00rootroot00000000000000/* exfatfs.h (29.08.09) Definitions of structures and constants used in exFAT file system. Free exFAT implementation. Copyright (C) 2010-2014 Andrew Nayenko This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef EXFATFS_H_INCLUDED #define EXFATFS_H_INCLUDED #include "byteorder.h" typedef uint32_t cluster_t; /* cluster number */ #define EXFAT_FIRST_DATA_CLUSTER 2 #define EXFAT_LAST_DATA_CLUSTER 0xfffffff6 #define EXFAT_CLUSTER_FREE 0 /* free cluster */ #define EXFAT_CLUSTER_BAD 0xfffffff7 /* cluster contains bad sector */ #define EXFAT_CLUSTER_END 0xffffffff /* final cluster of file or directory */ #define EXFAT_STATE_MOUNTED 2 struct exfat_super_block { uint8_t jump[3]; /* 0x00 jmp and nop instructions */ uint8_t oem_name[8]; /* 0x03 "EXFAT " */ uint8_t __unused1[53]; /* 0x0B always 0 */ le64_t sector_start; /* 0x40 partition first sector */ le64_t sector_count; /* 0x48 partition sectors count */ le32_t fat_sector_start; /* 0x50 FAT first sector */ le32_t fat_sector_count; /* 0x54 FAT sectors count */ le32_t cluster_sector_start; /* 0x58 first cluster sector */ le32_t cluster_count; /* 0x5C total clusters count */ le32_t rootdir_cluster; /* 0x60 first cluster of the root dir */ le32_t volume_serial; /* 0x64 volume serial number */ struct /* 0x68 FS version */ { uint8_t minor; uint8_t major; } version; le16_t volume_state; /* 0x6A volume state flags */ uint8_t sector_bits; /* 0x6C sector size as (1 << n) */ uint8_t spc_bits; /* 0x6D sectors per cluster as (1 << n) */ uint8_t fat_count; /* 0x6E always 1 */ uint8_t drive_no; /* 0x6F always 0x80 */ uint8_t allocated_percent; /* 0x70 percentage of allocated space */ uint8_t __unused2[397]; /* 0x71 always 0 */ le16_t boot_signature; /* the value of 0xAA55 */ } PACKED; STATIC_ASSERT(sizeof(struct exfat_super_block) == 512); #define EXFAT_ENTRY_VALID 0x80 #define EXFAT_ENTRY_CONTINUED 0x40 #define EXFAT_ENTRY_BITMAP (0x01 | EXFAT_ENTRY_VALID) #define EXFAT_ENTRY_UPCASE (0x02 | EXFAT_ENTRY_VALID) #define EXFAT_ENTRY_LABEL (0x03 | EXFAT_ENTRY_VALID) #define EXFAT_ENTRY_FILE (0x05 | EXFAT_ENTRY_VALID) #define EXFAT_ENTRY_FILE_INFO (0x00 | EXFAT_ENTRY_VALID | EXFAT_ENTRY_CONTINUED) #define EXFAT_ENTRY_FILE_NAME (0x01 | EXFAT_ENTRY_VALID | EXFAT_ENTRY_CONTINUED) struct exfat_entry /* common container for all entries */ { uint8_t type; /* any of EXFAT_ENTRY_xxx */ uint8_t data[31]; } PACKED; STATIC_ASSERT(sizeof(struct exfat_entry) == 32); #define EXFAT_ENAME_MAX 15 struct exfat_entry_bitmap /* allocated clusters bitmap */ { uint8_t type; /* EXFAT_ENTRY_BITMAP */ uint8_t __unknown1[19]; le32_t start_cluster; le64_t size; /* in bytes */ } PACKED; STATIC_ASSERT(sizeof(struct exfat_entry_bitmap) == 32); struct exfat_entry_upcase /* upper case translation table */ { uint8_t type; /* EXFAT_ENTRY_UPCASE */ uint8_t __unknown1[3]; le32_t checksum; uint8_t __unknown2[12]; le32_t start_cluster; le64_t size; /* in bytes */ } PACKED; STATIC_ASSERT(sizeof(struct exfat_entry_upcase) == 32); struct exfat_entry_label /* volume label */ { uint8_t type; /* EXFAT_ENTRY_LABEL */ uint8_t length; /* number of characters */ le16_t name[EXFAT_ENAME_MAX]; /* in UTF-16LE */ } PACKED; STATIC_ASSERT(sizeof(struct exfat_entry_label) == 32); #define EXFAT_ATTRIB_RO 0x01 #define EXFAT_ATTRIB_HIDDEN 0x02 #define EXFAT_ATTRIB_SYSTEM 0x04 #define EXFAT_ATTRIB_VOLUME 0x08 #define EXFAT_ATTRIB_DIR 0x10 #define EXFAT_ATTRIB_ARCH 0x20 struct exfat_entry_meta1 /* file or directory info (part 1) */ { uint8_t type; /* EXFAT_ENTRY_FILE */ uint8_t continuations; le16_t checksum; le16_t attrib; /* combination of EXFAT_ATTRIB_xxx */ le16_t __unknown1; le16_t crtime, crdate; /* creation date and time */ le16_t mtime, mdate; /* latest modification date and time */ le16_t atime, adate; /* latest access date and time */ uint8_t crtime_cs; /* creation time in cs (centiseconds) */ uint8_t mtime_cs; /* latest modification time in cs */ uint8_t __unknown2[10]; } PACKED; STATIC_ASSERT(sizeof(struct exfat_entry_meta1) == 32); #define EXFAT_FLAG_ALWAYS1 (1u << 0) #define EXFAT_FLAG_CONTIGUOUS (1u << 1) struct exfat_entry_meta2 /* file or directory info (part 2) */ { uint8_t type; /* EXFAT_ENTRY_FILE_INFO */ uint8_t flags; /* combination of EXFAT_FLAG_xxx */ uint8_t __unknown1; uint8_t name_length; le16_t name_hash; le16_t __unknown2; le64_t valid_size; /* in bytes, less or equal to size */ uint8_t __unknown3[4]; le32_t start_cluster; le64_t size; /* in bytes */ } PACKED; STATIC_ASSERT(sizeof(struct exfat_entry_meta2) == 32); struct exfat_entry_name /* file or directory name */ { uint8_t type; /* EXFAT_ENTRY_FILE_NAME */ uint8_t __unknown; le16_t name[EXFAT_ENAME_MAX]; /* in UTF-16LE */ } PACKED; STATIC_ASSERT(sizeof(struct exfat_entry_name) == 32); #endif /* ifndef EXFATFS_H_INCLUDED */ partclone-0.2.86/src/exfat/io.c000066400000000000000000000224571262102574200162620ustar00rootroot00000000000000/* io.c (02.09.09) exFAT file system implementation library. Free exFAT implementation. Copyright (C) 2010-2014 Andrew Nayenko This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "exfat.h" #include #include #include #include #include #include #include #if defined(__APPLE__) #include #elif defined(__OpenBSD__) #include #include #include #include #endif #include #ifdef USE_UBLIO #include #include #endif struct exfat_dev { int fd; enum exfat_mode mode; off_t size; /* in bytes */ #ifdef USE_UBLIO off_t pos; ublio_filehandle_t ufh; #endif }; static int open_ro(const char* spec) { return open(spec, O_RDONLY); } static int open_rw(const char* spec) { int fd = open(spec, O_RDWR); #ifdef __linux__ int ro = 0; /* This ioctl is needed because after "blockdev --setro" kernel still allows to open the device in read-write mode but fails writes. */ if (fd != -1 && ioctl(fd, BLKROGET, &ro) == 0 && ro) { close(fd); errno = EROFS; return -1; } #endif return fd; } struct exfat_dev* exfat_open(const char* spec, enum exfat_mode mode) { struct exfat_dev* dev; struct stat stbuf; #ifdef USE_UBLIO struct ublio_param up; #endif dev = malloc(sizeof(struct exfat_dev)); if (dev == NULL) { exfat_error("failed to allocate memory for device structure"); return NULL; } switch (mode) { case EXFAT_MODE_RO: dev->fd = open_ro(spec); if (dev->fd == -1) { free(dev); exfat_error("failed to open '%s' in read-only mode: %s", spec, strerror(errno)); return NULL; } dev->mode = EXFAT_MODE_RO; break; case EXFAT_MODE_RW: dev->fd = open_rw(spec); if (dev->fd == -1) { free(dev); exfat_error("failed to open '%s' in read-write mode: %s", spec, strerror(errno)); return NULL; } dev->mode = EXFAT_MODE_RW; break; case EXFAT_MODE_ANY: dev->fd = open_rw(spec); if (dev->fd != -1) { dev->mode = EXFAT_MODE_RW; break; } dev->fd = open_ro(spec); if (dev->fd != -1) { dev->mode = EXFAT_MODE_RO; exfat_warn("'%s' is write-protected, mounting read-only", spec); break; } free(dev); exfat_error("failed to open '%s': %s", spec, strerror(errno)); return NULL; } if (fstat(dev->fd, &stbuf) != 0) { close(dev->fd); free(dev); exfat_error("failed to fstat '%s'", spec); return NULL; } if (!S_ISBLK(stbuf.st_mode) && !S_ISCHR(stbuf.st_mode) && !S_ISREG(stbuf.st_mode)) { close(dev->fd); free(dev); exfat_error("'%s' is neither a device, nor a regular file", spec); return NULL; } #if defined(__APPLE__) if (!S_ISREG(stbuf.st_mode)) { uint32_t block_size = 0; uint64_t blocks = 0; if (ioctl(dev->fd, DKIOCGETBLOCKSIZE, &block_size) != 0) { close(dev->fd); free(dev); exfat_error("failed to get block size"); return NULL; } if (ioctl(dev->fd, DKIOCGETBLOCKCOUNT, &blocks) != 0) { close(dev->fd); free(dev); exfat_error("failed to get blocks count"); return NULL; } dev->size = blocks * block_size; } else #elif defined(__OpenBSD__) if (!S_ISREG(stbuf.st_mode)) { struct disklabel lab; struct partition* pp; char* partition; if (ioctl(dev->fd, DIOCGDINFO, &lab) == -1) { close(dev->fd); free(dev); exfat_error("failed to get disklabel"); return NULL; } /* Don't need to check that partition letter is valid as we won't get this far otherwise. */ partition = strchr(spec, '\0') - 1; pp = &(lab.d_partitions[*partition - 'a']); dev->size = DL_GETPSIZE(pp) * lab.d_secsize; if (pp->p_fstype != FS_NTFS) exfat_warn("partition type is not 0x07 (NTFS/exFAT); " "you can fix this with fdisk(8)"); } else #endif { /* works for Linux, FreeBSD, Solaris */ dev->size = exfat_seek(dev, 0, SEEK_END); if (dev->size <= 0) { close(dev->fd); free(dev); exfat_error("failed to get size of '%s'", spec); return NULL; } if (exfat_seek(dev, 0, SEEK_SET) == -1) { close(dev->fd); free(dev); exfat_error("failed to seek to the beginning of '%s'", spec); return NULL; } } #ifdef USE_UBLIO memset(&up, 0, sizeof(struct ublio_param)); up.up_blocksize = 256 * 1024; up.up_items = 64; up.up_grace = 32; up.up_priv = &dev->fd; dev->pos = 0; dev->ufh = ublio_open(&up); if (dev->ufh == NULL) { close(dev->fd); free(dev); exfat_error("failed to initialize ublio"); return NULL; } #endif return dev; } int exfat_close(struct exfat_dev* dev) { int rc = 0; #ifdef USE_UBLIO if (ublio_close(dev->ufh) != 0) { exfat_error("failed to close ublio"); rc = -EIO; } #endif if (close(dev->fd) != 0) { exfat_error("failed to close device: %s", strerror(errno)); rc = -EIO; } free(dev); return rc; } int exfat_fsync(struct exfat_dev* dev) { int rc = 0; #ifdef USE_UBLIO if (ublio_fsync(dev->ufh) != 0) { exfat_error("ublio fsync failed"); rc = -EIO; } #endif if (fsync(dev->fd) != 0) { exfat_error("fsync failed: %s", strerror(errno)); rc = -EIO; } return rc; } enum exfat_mode exfat_get_mode(const struct exfat_dev* dev) { return dev->mode; } off_t exfat_get_size(const struct exfat_dev* dev) { return dev->size; } off_t exfat_seek(struct exfat_dev* dev, off_t offset, int whence) { #ifdef USE_UBLIO /* XXX SEEK_CUR will be handled incorrectly */ return dev->pos = lseek(dev->fd, offset, whence); #else return lseek(dev->fd, offset, whence); #endif } ssize_t exfat_read(struct exfat_dev* dev, void* buffer, size_t size) { #ifdef USE_UBLIO ssize_t result = ublio_pread(dev->ufh, buffer, size, dev->pos); if (result >= 0) dev->pos += size; return result; #else return read(dev->fd, buffer, size); #endif } ssize_t exfat_write(struct exfat_dev* dev, const void* buffer, size_t size) { #ifdef USE_UBLIO ssize_t result = ublio_pwrite(dev->ufh, buffer, size, dev->pos); if (result >= 0) dev->pos += size; return result; #else return write(dev->fd, buffer, size); #endif } ssize_t exfat_pread(struct exfat_dev* dev, void* buffer, size_t size, off_t offset) { #ifdef USE_UBLIO return ublio_pread(dev->ufh, buffer, size, offset); #else return pread(dev->fd, buffer, size, offset); #endif } ssize_t exfat_pwrite(struct exfat_dev* dev, const void* buffer, size_t size, off_t offset) { #ifdef USE_UBLIO return ublio_pwrite(dev->ufh, buffer, size, offset); #else return pwrite(dev->fd, buffer, size, offset); #endif } ssize_t exfat_generic_pread(const struct exfat* ef, struct exfat_node* node, void* buffer, size_t size, off_t offset) { cluster_t cluster; char* bufp = buffer; off_t lsize, loffset, remainder; if (offset >= node->size) return 0; if (size == 0) return 0; cluster = exfat_advance_cluster(ef, node, offset / CLUSTER_SIZE(*ef->sb)); if (CLUSTER_INVALID(cluster)) { exfat_error("invalid cluster 0x%x while reading", cluster); return -1; } loffset = offset % CLUSTER_SIZE(*ef->sb); remainder = MIN(size, node->size - offset); while (remainder > 0) { if (CLUSTER_INVALID(cluster)) { exfat_error("invalid cluster 0x%x while reading", cluster); return -1; } lsize = MIN(CLUSTER_SIZE(*ef->sb) - loffset, remainder); if (exfat_pread(ef->dev, bufp, lsize, exfat_c2o(ef, cluster) + loffset) < 0) { exfat_error("failed to read cluster %#x", cluster); return -1; } bufp += lsize; loffset = 0; remainder -= lsize; cluster = exfat_next_cluster(ef, node, cluster); } if (!ef->ro && !ef->noatime) exfat_update_atime(node); return MIN(size, node->size - offset) - remainder; } ssize_t exfat_generic_pwrite(struct exfat* ef, struct exfat_node* node, const void* buffer, size_t size, off_t offset) { cluster_t cluster; const char* bufp = buffer; off_t lsize, loffset, remainder; if (offset > node->size) if (exfat_truncate(ef, node, offset, true) != 0) return -1; if (offset + size > node->size) if (exfat_truncate(ef, node, offset + size, false) != 0) return -1; if (size == 0) return 0; cluster = exfat_advance_cluster(ef, node, offset / CLUSTER_SIZE(*ef->sb)); if (CLUSTER_INVALID(cluster)) { exfat_error("invalid cluster 0x%x while writing", cluster); return -1; } loffset = offset % CLUSTER_SIZE(*ef->sb); remainder = size; while (remainder > 0) { if (CLUSTER_INVALID(cluster)) { exfat_error("invalid cluster 0x%x while writing", cluster); return -1; } lsize = MIN(CLUSTER_SIZE(*ef->sb) - loffset, remainder); if (exfat_pwrite(ef->dev, bufp, lsize, exfat_c2o(ef, cluster) + loffset) < 0) { exfat_error("failed to write cluster %#x", cluster); return -1; } bufp += lsize; loffset = 0; remainder -= lsize; cluster = exfat_next_cluster(ef, node, cluster); } exfat_update_mtime(node); return size - remainder; } partclone-0.2.86/src/exfat/log.c000066400000000000000000000044331262102574200164260ustar00rootroot00000000000000/* log.c (02.09.09) exFAT file system implementation library. Free exFAT implementation. Copyright (C) 2010-2014 Andrew Nayenko This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "exfat.h" #include #include #include int exfat_errors; /* * This message means an internal bug in exFAT implementation. */ void exfat_bug(const char* format, ...) { va_list ap, aq; va_start(ap, format); va_copy(aq, ap); fflush(stdout); fputs("BUG: ", stderr); vfprintf(stderr, format, ap); va_end(ap); fputs(".\n", stderr); if (!isatty(STDERR_FILENO)) vsyslog(LOG_CRIT, format, aq); va_end(aq); abort(); } /* * This message means an error in exFAT file system. */ void exfat_error(const char* format, ...) { va_list ap, aq; exfat_errors++; va_start(ap, format); va_copy(aq, ap); fflush(stdout); fputs("ERROR: ", stderr); vfprintf(stderr, format, ap); va_end(ap); fputs(".\n", stderr); if (!isatty(STDERR_FILENO)) vsyslog(LOG_ERR, format, aq); va_end(aq); } /* * This message means that there is something unexpected in exFAT file system * that can be a potential problem. */ void exfat_warn(const char* format, ...) { va_list ap, aq; va_start(ap, format); va_copy(aq, ap); fflush(stdout); fputs("WARN: ", stderr); vfprintf(stderr, format, ap); va_end(ap); fputs(".\n", stderr); if (!isatty(STDERR_FILENO)) vsyslog(LOG_WARNING, format, aq); va_end(aq); } /* * Just debug message. Disabled by default. */ void exfat_debug(const char* format, ...) { va_list ap; fflush(stdout); fputs("DEBUG: ", stderr); va_start(ap, format); vfprintf(stderr, format, ap); va_end(ap); fputs(".\n", stderr); } partclone-0.2.86/src/exfat/lookup.c000066400000000000000000000114251262102574200171550ustar00rootroot00000000000000/* lookup.c (02.09.09) exFAT file system implementation library. Free exFAT implementation. Copyright (C) 2010-2014 Andrew Nayenko This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "exfat.h" #include #include #include int exfat_opendir(struct exfat* ef, struct exfat_node* dir, struct exfat_iterator* it) { int rc; exfat_get_node(dir); it->parent = dir; it->current = NULL; rc = exfat_cache_directory(ef, dir); if (rc != 0) exfat_put_node(ef, dir); return rc; } void exfat_closedir(struct exfat* ef, struct exfat_iterator* it) { exfat_put_node(ef, it->parent); it->parent = NULL; it->current = NULL; } struct exfat_node* exfat_readdir(struct exfat* ef, struct exfat_iterator* it) { if (it->current == NULL) it->current = it->parent->child; else it->current = it->current->next; if (it->current != NULL) return exfat_get_node(it->current); else return NULL; } static int compare_char(struct exfat* ef, uint16_t a, uint16_t b) { if (a >= ef->upcase_chars || b >= ef->upcase_chars) return (int) a - (int) b; return (int) le16_to_cpu(ef->upcase[a]) - (int) le16_to_cpu(ef->upcase[b]); } static int compare_name(struct exfat* ef, const le16_t* a, const le16_t* b) { while (le16_to_cpu(*a) && le16_to_cpu(*b)) { int rc = compare_char(ef, le16_to_cpu(*a), le16_to_cpu(*b)); if (rc != 0) return rc; a++; b++; } return compare_char(ef, le16_to_cpu(*a), le16_to_cpu(*b)); } static int lookup_name(struct exfat* ef, struct exfat_node* parent, struct exfat_node** node, const char* name, size_t n) { struct exfat_iterator it; le16_t buffer[EXFAT_NAME_MAX + 1]; int rc; *node = NULL; rc = utf8_to_utf16(buffer, name, EXFAT_NAME_MAX, n); if (rc != 0) return rc; rc = exfat_opendir(ef, parent, &it); if (rc != 0) return rc; while ((*node = exfat_readdir(ef, &it))) { if (compare_name(ef, buffer, (*node)->name) == 0) { exfat_closedir(ef, &it); return 0; } exfat_put_node(ef, *node); } exfat_closedir(ef, &it); return -ENOENT; } static size_t get_comp(const char* path, const char** comp) { const char* end; *comp = path + strspn(path, "/"); /* skip leading slashes */ end = strchr(*comp, '/'); if (end == NULL) return strlen(*comp); else return end - *comp; } int exfat_lookup(struct exfat* ef, struct exfat_node** node, const char* path) { struct exfat_node* parent; const char* p; size_t n; int rc; /* start from the root directory */ parent = *node = exfat_get_node(ef->root); for (p = path; (n = get_comp(p, &p)); p += n) { if (n == 1 && *p == '.') /* skip "." component */ continue; rc = lookup_name(ef, parent, node, p, n); if (rc != 0) { exfat_put_node(ef, parent); return rc; } exfat_put_node(ef, parent); parent = *node; } return 0; } static bool is_last_comp(const char* comp, size_t length) { const char* p = comp + length; return get_comp(p, &p) == 0; } static bool is_allowed(const char* comp, size_t length) { size_t i; for (i = 0; i < length; i++) switch (comp[i]) { case 0x01 ... 0x1f: case '/': case '\\': case ':': case '*': case '?': case '"': case '<': case '>': case '|': return false; } return true; } int exfat_split(struct exfat* ef, struct exfat_node** parent, struct exfat_node** node, le16_t* name, const char* path) { const char* p; size_t n; int rc; memset(name, 0, (EXFAT_NAME_MAX + 1) * sizeof(le16_t)); *parent = *node = exfat_get_node(ef->root); for (p = path; (n = get_comp(p, &p)); p += n) { if (n == 1 && *p == '.') continue; if (is_last_comp(p, n)) { if (!is_allowed(p, n)) { /* contains characters that are not allowed */ exfat_put_node(ef, *parent); return -ENOENT; } rc = utf8_to_utf16(name, p, EXFAT_NAME_MAX, n); if (rc != 0) { exfat_put_node(ef, *parent); return rc; } rc = lookup_name(ef, *parent, node, p, n); if (rc != 0 && rc != -ENOENT) { exfat_put_node(ef, *parent); return rc; } return 0; } rc = lookup_name(ef, *parent, node, p, n); if (rc != 0) { exfat_put_node(ef, *parent); return rc; } exfat_put_node(ef, *parent); *parent = *node; } exfat_bug("impossible"); } partclone-0.2.86/src/exfat/mount.c000066400000000000000000000225211262102574200170050ustar00rootroot00000000000000/* mount.c (22.10.09) exFAT file system implementation library. Free exFAT implementation. Copyright (C) 2010-2014 Andrew Nayenko This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "exfat.h" #include #include #include #include #include #include static uint64_t rootdir_size(const struct exfat* ef) { uint64_t clusters = 0; cluster_t rootdir_cluster = le32_to_cpu(ef->sb->rootdir_cluster); while (!CLUSTER_INVALID(rootdir_cluster)) { clusters++; /* root directory cannot be contiguous because there is no flag to indicate this */ rootdir_cluster = exfat_next_cluster(ef, ef->root, rootdir_cluster); } if (rootdir_cluster != EXFAT_CLUSTER_END) { exfat_error("bad cluster %#x while reading root directory", rootdir_cluster); return 0; } return clusters * CLUSTER_SIZE(*ef->sb); } static const char* get_option(const char* options, const char* option_name) { const char* p; size_t length = strlen(option_name); for (p = strstr(options, option_name); p; p = strstr(p + 1, option_name)) if ((p == options || p[-1] == ',') && p[length] == '=') return p + length + 1; return NULL; } static int get_int_option(const char* options, const char* option_name, int base, int default_value) { const char* p = get_option(options, option_name); if (p == NULL) return default_value; return strtol(p, NULL, base); } static bool match_option(const char* options, const char* option_name) { const char* p; size_t length = strlen(option_name); for (p = strstr(options, option_name); p; p = strstr(p + 1, option_name)) if ((p == options || p[-1] == ',') && (p[length] == ',' || p[length] == '\0')) return true; return false; } static void parse_options(struct exfat* ef, const char* options) { int sys_umask = umask(0); int opt_umask; umask(sys_umask); /* restore umask */ opt_umask = get_int_option(options, "umask", 8, sys_umask); ef->dmask = get_int_option(options, "dmask", 8, opt_umask) & 0777; ef->fmask = get_int_option(options, "fmask", 8, opt_umask) & 0777; ef->uid = get_int_option(options, "uid", 10, geteuid()); ef->gid = get_int_option(options, "gid", 10, getegid()); ef->noatime = match_option(options, "noatime"); } static bool verify_vbr_checksum(struct exfat_dev* dev, void* sector, off_t sector_size) { uint32_t vbr_checksum; int i; if (exfat_pread(dev, sector, sector_size, 0) < 0) { exfat_error("failed to read boot sector"); return false; } vbr_checksum = exfat_vbr_start_checksum(sector, sector_size); for (i = 1; i < 11; i++) { if (exfat_pread(dev, sector, sector_size, i * sector_size) < 0) { exfat_error("failed to read VBR sector"); return false; } vbr_checksum = exfat_vbr_add_checksum(sector, sector_size, vbr_checksum); } if (exfat_pread(dev, sector, sector_size, i * sector_size) < 0) { exfat_error("failed to read VBR checksum sector"); return false; } for (i = 0; i < sector_size / sizeof(vbr_checksum); i++) if (le32_to_cpu(((const le32_t*) sector)[i]) != vbr_checksum) { exfat_error("invalid VBR checksum 0x%x (expected 0x%x)", le32_to_cpu(((const le32_t*) sector)[i]), vbr_checksum); return false; } return true; } static int commit_super_block(const struct exfat* ef) { if (exfat_pwrite(ef->dev, ef->sb, sizeof(struct exfat_super_block), 0) < 0) { exfat_error("failed to write super block"); return 1; } return exfat_fsync(ef->dev); } static int prepare_super_block(const struct exfat* ef) { if (le16_to_cpu(ef->sb->volume_state) & EXFAT_STATE_MOUNTED) exfat_warn("volume was not unmounted cleanly"); if (ef->ro) return 0; ef->sb->volume_state = cpu_to_le16( le16_to_cpu(ef->sb->volume_state) | EXFAT_STATE_MOUNTED); return commit_super_block(ef); } int exfat_mount(struct exfat* ef, const char* spec, const char* options) { int rc; enum exfat_mode mode; exfat_tzset(); memset(ef, 0, sizeof(struct exfat)); parse_options(ef, options); if (match_option(options, "ro")) mode = EXFAT_MODE_RO; else if (match_option(options, "ro_fallback")) mode = EXFAT_MODE_ANY; else mode = EXFAT_MODE_RW; ef->dev = exfat_open(spec, mode); if (ef->dev == NULL) return -EIO; if (exfat_get_mode(ef->dev) == EXFAT_MODE_RO) { if (mode == EXFAT_MODE_ANY) ef->ro = -1; else ef->ro = 1; } ef->sb = malloc(sizeof(struct exfat_super_block)); if (ef->sb == NULL) { exfat_close(ef->dev); exfat_error("failed to allocate memory for the super block"); return -ENOMEM; } memset(ef->sb, 0, sizeof(struct exfat_super_block)); if (exfat_pread(ef->dev, ef->sb, sizeof(struct exfat_super_block), 0) < 0) { exfat_close(ef->dev); free(ef->sb); exfat_error("failed to read boot sector"); return -EIO; } if (memcmp(ef->sb->oem_name, "EXFAT ", 8) != 0) { exfat_close(ef->dev); free(ef->sb); exfat_error("exFAT file system is not found"); return -EIO; } ef->zero_cluster = malloc(CLUSTER_SIZE(*ef->sb)); if (ef->zero_cluster == NULL) { exfat_close(ef->dev); free(ef->sb); exfat_error("failed to allocate zero sector"); return -ENOMEM; } /* use zero_cluster as a temporary buffer for VBR checksum verification */ if (!verify_vbr_checksum(ef->dev, ef->zero_cluster, SECTOR_SIZE(*ef->sb))) { free(ef->zero_cluster); exfat_close(ef->dev); free(ef->sb); return -EIO; } memset(ef->zero_cluster, 0, CLUSTER_SIZE(*ef->sb)); if (ef->sb->version.major != 1 || ef->sb->version.minor != 0) { free(ef->zero_cluster); exfat_close(ef->dev); exfat_error("unsupported exFAT version: %hhu.%hhu", ef->sb->version.major, ef->sb->version.minor); free(ef->sb); return -EIO; } if (ef->sb->fat_count != 1) { free(ef->zero_cluster); exfat_close(ef->dev); exfat_error("unsupported FAT count: %hhu", ef->sb->fat_count); free(ef->sb); return -EIO; } /* officially exFAT supports cluster size up to 32 MB */ if ((int) ef->sb->sector_bits + (int) ef->sb->spc_bits > 25) { free(ef->zero_cluster); exfat_close(ef->dev); exfat_error("too big cluster size: 2^%d", (int) ef->sb->sector_bits + (int) ef->sb->spc_bits); free(ef->sb); return -EIO; } if (le64_to_cpu(ef->sb->sector_count) * SECTOR_SIZE(*ef->sb) > exfat_get_size(ef->dev)) { free(ef->zero_cluster); exfat_error("file system is larger than underlying device: " "%"PRIu64" > %"PRIu64, le64_to_cpu(ef->sb->sector_count) * SECTOR_SIZE(*ef->sb), exfat_get_size(ef->dev)); exfat_close(ef->dev); free(ef->sb); return -EIO; } ef->root = malloc(sizeof(struct exfat_node)); if (ef->root == NULL) { free(ef->zero_cluster); exfat_close(ef->dev); free(ef->sb); exfat_error("failed to allocate root node"); return -ENOMEM; } memset(ef->root, 0, sizeof(struct exfat_node)); ef->root->flags = EXFAT_ATTRIB_DIR; ef->root->start_cluster = le32_to_cpu(ef->sb->rootdir_cluster); ef->root->fptr_cluster = ef->root->start_cluster; ef->root->name[0] = cpu_to_le16('\0'); ef->root->size = rootdir_size(ef); if (ef->root->size == 0) { free(ef->root); free(ef->zero_cluster); exfat_close(ef->dev); free(ef->sb); return -EIO; } /* exFAT does not have time attributes for the root directory */ ef->root->mtime = 0; ef->root->atime = 0; /* always keep at least 1 reference to the root node */ exfat_get_node(ef->root); rc = exfat_cache_directory(ef, ef->root); if (rc != 0) goto error; if (ef->upcase == NULL) { exfat_error("upcase table is not found"); goto error; } if (ef->cmap.chunk == NULL) { exfat_error("clusters bitmap is not found"); goto error; } if (prepare_super_block(ef) != 0) goto error; return 0; error: exfat_put_node(ef, ef->root); exfat_reset_cache(ef); free(ef->root); free(ef->zero_cluster); exfat_close(ef->dev); free(ef->sb); return -EIO; } static void finalize_super_block(struct exfat* ef) { if (ef->ro) return; ef->sb->volume_state = cpu_to_le16( le16_to_cpu(ef->sb->volume_state) & ~EXFAT_STATE_MOUNTED); /* Some implementations set the percentage of allocated space to 0xff on FS creation and never update it. In this case leave it as is. */ if (ef->sb->allocated_percent != 0xff) { uint32_t free, total; free = exfat_count_free_clusters(ef); total = le32_to_cpu(ef->sb->cluster_count); ef->sb->allocated_percent = ((total - free) * 100 + total / 2) / total; } commit_super_block(ef); /* ignore return code */ } void exfat_unmount(struct exfat* ef) { exfat_flush(ef); /* ignore return code */ exfat_put_node(ef, ef->root); exfat_reset_cache(ef); free(ef->root); ef->root = NULL; finalize_super_block(ef); exfat_close(ef->dev); /* close descriptor immediately after fsync */ ef->dev = NULL; free(ef->zero_cluster); ef->zero_cluster = NULL; free(ef->cmap.chunk); ef->cmap.chunk = NULL; free(ef->sb); ef->sb = NULL; free(ef->upcase); ef->upcase = NULL; ef->upcase_chars = 0; } partclone-0.2.86/src/exfat/node.c000066400000000000000000000752221262102574200165760ustar00rootroot00000000000000/* node.c (09.10.09) exFAT file system implementation library. Free exFAT implementation. Copyright (C) 2010-2014 Andrew Nayenko This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "exfat.h" #include #include #include /* on-disk nodes iterator */ struct iterator { cluster_t cluster; off_t offset; int contiguous; char* chunk; }; struct exfat_node* exfat_get_node(struct exfat_node* node) { /* if we switch to multi-threaded mode we will need atomic increment here and atomic decrement in exfat_put_node() */ node->references++; return node; } void exfat_put_node(struct exfat* ef, struct exfat_node* node) { char buffer[UTF8_BYTES(EXFAT_NAME_MAX) + 1]; --node->references; if (node->references < 0) { exfat_get_name(node, buffer, sizeof(buffer) - 1); exfat_bug("reference counter of '%s' is below zero", buffer); } else if (node->references == 0 && node != ef->root) { if (node->flags & EXFAT_ATTRIB_DIRTY) { exfat_get_name(node, buffer, sizeof(buffer) - 1); exfat_warn("dirty node '%s' with zero references", buffer); } } } /** * This function must be called on rmdir and unlink (after the last * exfat_put_node()) to free clusters. */ int exfat_cleanup_node(struct exfat* ef, struct exfat_node* node) { int rc = 0; if (node->references != 0) exfat_bug("unable to cleanup a node with %d references", node->references); if (node->flags & EXFAT_ATTRIB_UNLINKED) { /* free all clusters and node structure itself */ rc = exfat_truncate(ef, node, 0, true); /* free the node even in case of error or its memory will be lost */ free(node); } return rc; } /** * Cluster + offset from the beginning of the directory to absolute offset. */ static off_t co2o(struct exfat* ef, cluster_t cluster, off_t offset) { return exfat_c2o(ef, cluster) + offset % CLUSTER_SIZE(*ef->sb); } static int opendir(struct exfat* ef, const struct exfat_node* dir, struct iterator* it) { if (!(dir->flags & EXFAT_ATTRIB_DIR)) exfat_bug("not a directory"); it->cluster = dir->start_cluster; it->offset = 0; it->contiguous = IS_CONTIGUOUS(*dir); it->chunk = malloc(CLUSTER_SIZE(*ef->sb)); if (it->chunk == NULL) { exfat_error("out of memory"); return -ENOMEM; } if (exfat_pread(ef->dev, it->chunk, CLUSTER_SIZE(*ef->sb), exfat_c2o(ef, it->cluster)) < 0) { exfat_error("failed to read directory cluster %#x", it->cluster); return -EIO; } return 0; } static void closedir(struct iterator* it) { it->cluster = 0; it->offset = 0; it->contiguous = 0; free(it->chunk); it->chunk = NULL; } static bool fetch_next_entry(struct exfat* ef, const struct exfat_node* parent, struct iterator* it) { /* move iterator to the next entry in the directory */ it->offset += sizeof(struct exfat_entry); /* fetch the next cluster if needed */ if ((it->offset & (CLUSTER_SIZE(*ef->sb) - 1)) == 0) { /* reached the end of directory; the caller should check this condition too */ if (it->offset >= parent->size) return true; it->cluster = exfat_next_cluster(ef, parent, it->cluster); if (CLUSTER_INVALID(it->cluster)) { exfat_error("invalid cluster 0x%x while reading directory", it->cluster); return false; } if (exfat_pread(ef->dev, it->chunk, CLUSTER_SIZE(*ef->sb), exfat_c2o(ef, it->cluster)) < 0) { exfat_error("failed to read the next directory cluster %#x", it->cluster); return false; } } return true; } static struct exfat_node* allocate_node(void) { struct exfat_node* node = malloc(sizeof(struct exfat_node)); if (node == NULL) { exfat_error("failed to allocate node"); return NULL; } memset(node, 0, sizeof(struct exfat_node)); return node; } static void init_node_meta1(struct exfat_node* node, const struct exfat_entry_meta1* meta1) { node->flags = le16_to_cpu(meta1->attrib); node->mtime = exfat_exfat2unix(meta1->mdate, meta1->mtime, meta1->mtime_cs); /* there is no centiseconds field for atime */ node->atime = exfat_exfat2unix(meta1->adate, meta1->atime, 0); } static void init_node_meta2(struct exfat_node* node, const struct exfat_entry_meta2* meta2) { node->size = le64_to_cpu(meta2->size); node->start_cluster = le32_to_cpu(meta2->start_cluster); node->fptr_cluster = node->start_cluster; if (meta2->flags & EXFAT_FLAG_CONTIGUOUS) node->flags |= EXFAT_ATTRIB_CONTIGUOUS; } static const struct exfat_entry* get_entry_ptr(const struct exfat* ef, const struct iterator* it) { return (const struct exfat_entry*) (it->chunk + it->offset % CLUSTER_SIZE(*ef->sb)); } static bool check_node(const struct exfat_node* node, uint16_t actual_checksum, uint16_t reference_checksum, uint64_t valid_size) { char buffer[UTF8_BYTES(EXFAT_NAME_MAX) + 1]; /* Validate checksum first. If it's invalid all other fields probably contain just garbage. */ if (actual_checksum != reference_checksum) { exfat_get_name(node, buffer, sizeof(buffer) - 1); exfat_error("'%s' has invalid checksum (%#hx != %#hx)", buffer, actual_checksum, reference_checksum); return false; } /* exFAT does not support sparse files but allows files with uninitialized clusters. For such files valid_size means initialized data size and cannot be greater than file size. See SetFileValidData() function description in MSDN. */ if (valid_size > node->size) { exfat_get_name(node, buffer, sizeof(buffer) - 1); exfat_error("'%s' has valid size (%"PRIu64") greater than size " "(%"PRIu64")", buffer, valid_size, node->size); return false; } return true; } /* * Reads one entry in directory at position pointed by iterator and fills * node structure. */ static int readdir(struct exfat* ef, const struct exfat_node* parent, struct exfat_node** node, struct iterator* it) { int rc = -EIO; const struct exfat_entry* entry; const struct exfat_entry_meta1* meta1; const struct exfat_entry_meta2* meta2; const struct exfat_entry_name* file_name; const struct exfat_entry_upcase* upcase; const struct exfat_entry_bitmap* bitmap; const struct exfat_entry_label* label; uint8_t continuations = 0; le16_t* namep = NULL; uint16_t reference_checksum = 0; uint16_t actual_checksum = 0; uint64_t valid_size = 0; *node = NULL; for (;;) { if (it->offset >= parent->size) { if (continuations != 0) { exfat_error("expected %hhu continuations", continuations); goto error; } return -ENOENT; /* that's OK, means end of directory */ } entry = get_entry_ptr(ef, it); switch (entry->type) { case EXFAT_ENTRY_FILE: if (continuations != 0) { exfat_error("expected %hhu continuations before new entry", continuations); goto error; } meta1 = (const struct exfat_entry_meta1*) entry; continuations = meta1->continuations; /* each file entry must have at least 2 continuations: info and name */ if (continuations < 2) { exfat_error("too few continuations (%hhu)", continuations); goto error; } if (continuations > 1 + DIV_ROUND_UP(EXFAT_NAME_MAX, EXFAT_ENAME_MAX)) { exfat_error("too many continuations (%hhu)", continuations); goto error; } reference_checksum = le16_to_cpu(meta1->checksum); actual_checksum = exfat_start_checksum(meta1); *node = allocate_node(); if (*node == NULL) { rc = -ENOMEM; goto error; } /* new node has zero reference counter */ (*node)->entry_cluster = it->cluster; (*node)->entry_offset = it->offset; init_node_meta1(*node, meta1); namep = (*node)->name; break; case EXFAT_ENTRY_FILE_INFO: if (continuations < 2) { exfat_error("unexpected continuation (%hhu)", continuations); goto error; } meta2 = (const struct exfat_entry_meta2*) entry; if (meta2->flags & ~(EXFAT_FLAG_ALWAYS1 | EXFAT_FLAG_CONTIGUOUS)) { exfat_error("unknown flags in meta2 (0x%hhx)", meta2->flags); goto error; } init_node_meta2(*node, meta2); actual_checksum = exfat_add_checksum(entry, actual_checksum); valid_size = le64_to_cpu(meta2->valid_size); /* empty files must be marked as non-contiguous */ if ((*node)->size == 0 && (meta2->flags & EXFAT_FLAG_CONTIGUOUS)) { exfat_error("empty file marked as contiguous (0x%hhx)", meta2->flags); goto error; } /* directories must be aligned on at cluster boundary */ if (((*node)->flags & EXFAT_ATTRIB_DIR) && (*node)->size % CLUSTER_SIZE(*ef->sb) != 0) { exfat_error("directory has invalid size %"PRIu64" bytes", (*node)->size); goto error; } --continuations; break; case EXFAT_ENTRY_FILE_NAME: if (continuations == 0) { exfat_error("unexpected continuation"); goto error; } file_name = (const struct exfat_entry_name*) entry; actual_checksum = exfat_add_checksum(entry, actual_checksum); memcpy(namep, file_name->name, MIN(EXFAT_ENAME_MAX, ((*node)->name + EXFAT_NAME_MAX - namep)) * sizeof(le16_t)); namep += EXFAT_ENAME_MAX; if (--continuations == 0) { if (!check_node(*node, actual_checksum, reference_checksum, valid_size)) goto error; if (!fetch_next_entry(ef, parent, it)) goto error; return 0; /* entry completed */ } break; case EXFAT_ENTRY_UPCASE: if (ef->upcase != NULL) break; upcase = (const struct exfat_entry_upcase*) entry; if (CLUSTER_INVALID(le32_to_cpu(upcase->start_cluster))) { exfat_error("invalid cluster 0x%x in upcase table", le32_to_cpu(upcase->start_cluster)); goto error; } if (le64_to_cpu(upcase->size) == 0 || le64_to_cpu(upcase->size) > 0xffff * sizeof(uint16_t) || le64_to_cpu(upcase->size) % sizeof(uint16_t) != 0) { exfat_error("bad upcase table size (%"PRIu64" bytes)", le64_to_cpu(upcase->size)); goto error; } ef->upcase = malloc(le64_to_cpu(upcase->size)); if (ef->upcase == NULL) { exfat_error("failed to allocate upcase table (%"PRIu64" bytes)", le64_to_cpu(upcase->size)); rc = -ENOMEM; goto error; } ef->upcase_chars = le64_to_cpu(upcase->size) / sizeof(le16_t); if (exfat_pread(ef->dev, ef->upcase, le64_to_cpu(upcase->size), exfat_c2o(ef, le32_to_cpu(upcase->start_cluster))) < 0) { exfat_error("failed to read upper case table " "(%"PRIu64" bytes starting at cluster %#x)", le64_to_cpu(upcase->size), le32_to_cpu(upcase->start_cluster)); goto error; } break; case EXFAT_ENTRY_BITMAP: bitmap = (const struct exfat_entry_bitmap*) entry; ef->cmap.start_cluster = le32_to_cpu(bitmap->start_cluster); if (CLUSTER_INVALID(ef->cmap.start_cluster)) { exfat_error("invalid cluster 0x%x in clusters bitmap", ef->cmap.start_cluster); goto error; } ef->cmap.size = le32_to_cpu(ef->sb->cluster_count) - EXFAT_FIRST_DATA_CLUSTER; if (le64_to_cpu(bitmap->size) < DIV_ROUND_UP(ef->cmap.size, 8)) { exfat_error("invalid clusters bitmap size: %"PRIu64 " (expected at least %u)", le64_to_cpu(bitmap->size), DIV_ROUND_UP(ef->cmap.size, 8)); goto error; } /* FIXME bitmap can be rather big, up to 512 MB */ ef->cmap.chunk_size = ef->cmap.size; ef->cmap.chunk = malloc(BMAP_SIZE(ef->cmap.chunk_size)); if (ef->cmap.chunk == NULL) { exfat_error("failed to allocate clusters bitmap chunk " "(%"PRIu64" bytes)", le64_to_cpu(bitmap->size)); rc = -ENOMEM; goto error; } if (exfat_pread(ef->dev, ef->cmap.chunk, BMAP_SIZE(ef->cmap.chunk_size), exfat_c2o(ef, ef->cmap.start_cluster)) < 0) { exfat_error("failed to read clusters bitmap " "(%"PRIu64" bytes starting at cluster %#x)", le64_to_cpu(bitmap->size), ef->cmap.start_cluster); goto error; } break; case EXFAT_ENTRY_LABEL: label = (const struct exfat_entry_label*) entry; if (label->length > EXFAT_ENAME_MAX) { exfat_error("too long label (%hhu chars)", label->length); goto error; } if (utf16_to_utf8(ef->label, label->name, sizeof(ef->label) - 1, EXFAT_ENAME_MAX) != 0) goto error; break; default: if (entry->type & EXFAT_ENTRY_VALID) { exfat_error("unknown entry type 0x%hhx", entry->type); goto error; } break; } if (!fetch_next_entry(ef, parent, it)) goto error; } /* we never reach here */ error: free(*node); *node = NULL; return rc; } int exfat_cache_directory(struct exfat* ef, struct exfat_node* dir) { struct iterator it; int rc; struct exfat_node* node; struct exfat_node* current = NULL; if (dir->flags & EXFAT_ATTRIB_CACHED) return 0; /* already cached */ rc = opendir(ef, dir, &it); if (rc != 0) return rc; while ((rc = readdir(ef, dir, &node, &it)) == 0) { node->parent = dir; if (current != NULL) { current->next = node; node->prev = current; } else dir->child = node; current = node; } closedir(&it); if (rc != -ENOENT) { /* rollback */ for (current = dir->child; current; current = node) { node = current->next; free(current); } dir->child = NULL; return rc; } dir->flags |= EXFAT_ATTRIB_CACHED; return 0; } static void tree_attach(struct exfat_node* dir, struct exfat_node* node) { node->parent = dir; if (dir->child) { dir->child->prev = node; node->next = dir->child; } dir->child = node; } static void tree_detach(struct exfat_node* node) { if (node->prev) node->prev->next = node->next; else /* this is the first node in the list */ node->parent->child = node->next; if (node->next) node->next->prev = node->prev; node->parent = NULL; node->prev = NULL; node->next = NULL; } static void reset_cache(struct exfat* ef, struct exfat_node* node) { char buffer[UTF8_BYTES(EXFAT_NAME_MAX) + 1]; while (node->child) { struct exfat_node* p = node->child; reset_cache(ef, p); tree_detach(p); free(p); } node->flags &= ~EXFAT_ATTRIB_CACHED; if (node->references != 0) { exfat_get_name(node, buffer, sizeof(buffer) - 1); exfat_warn("non-zero reference counter (%d) for '%s'", node->references, buffer); } if (node != ef->root && (node->flags & EXFAT_ATTRIB_DIRTY)) { exfat_get_name(node, buffer, sizeof(buffer) - 1); exfat_bug("node '%s' is dirty", buffer); } while (node->references) exfat_put_node(ef, node); } void exfat_reset_cache(struct exfat* ef) { reset_cache(ef, ef->root); } static bool next_entry(struct exfat* ef, const struct exfat_node* parent, cluster_t* cluster, off_t* offset) { *offset += sizeof(struct exfat_entry); if (*offset % CLUSTER_SIZE(*ef->sb) == 0) { *cluster = exfat_next_cluster(ef, parent, *cluster); if (CLUSTER_INVALID(*cluster)) { exfat_error("invalid cluster %#x while getting next entry", *cluster); return false; } } return true; } int exfat_flush_node(struct exfat* ef, struct exfat_node* node) { cluster_t cluster; off_t offset; off_t meta1_offset, meta2_offset; struct exfat_entry_meta1 meta1; struct exfat_entry_meta2 meta2; if (!(node->flags & EXFAT_ATTRIB_DIRTY)) return 0; /* no need to flush */ if (ef->ro) exfat_bug("unable to flush node to read-only FS"); if (node->parent == NULL) return 0; /* do not flush unlinked node */ cluster = node->entry_cluster; offset = node->entry_offset; meta1_offset = co2o(ef, cluster, offset); if (!next_entry(ef, node->parent, &cluster, &offset)) return -EIO; meta2_offset = co2o(ef, cluster, offset); if (exfat_pread(ef->dev, &meta1, sizeof(meta1), meta1_offset) < 0) { exfat_error("failed to read meta1 entry on flush"); return -EIO; } if (meta1.type != EXFAT_ENTRY_FILE) exfat_bug("invalid type of meta1: 0x%hhx", meta1.type); meta1.attrib = cpu_to_le16(node->flags); exfat_unix2exfat(node->mtime, &meta1.mdate, &meta1.mtime, &meta1.mtime_cs); exfat_unix2exfat(node->atime, &meta1.adate, &meta1.atime, NULL); if (exfat_pread(ef->dev, &meta2, sizeof(meta2), meta2_offset) < 0) { exfat_error("failed to read meta2 entry on flush"); return -EIO; } if (meta2.type != EXFAT_ENTRY_FILE_INFO) exfat_bug("invalid type of meta2: 0x%hhx", meta2.type); meta2.size = meta2.valid_size = cpu_to_le64(node->size); meta2.start_cluster = cpu_to_le32(node->start_cluster); meta2.flags = EXFAT_FLAG_ALWAYS1; /* empty files must not be marked as contiguous */ if (node->size != 0 && IS_CONTIGUOUS(*node)) meta2.flags |= EXFAT_FLAG_CONTIGUOUS; /* name hash remains unchanged, no need to recalculate it */ meta1.checksum = exfat_calc_checksum(&meta1, &meta2, node->name); if (exfat_pwrite(ef->dev, &meta1, sizeof(meta1), meta1_offset) < 0) { exfat_error("failed to write meta1 entry on flush"); return -EIO; } if (exfat_pwrite(ef->dev, &meta2, sizeof(meta2), meta2_offset) < 0) { exfat_error("failed to write meta2 entry on flush"); return -EIO; } node->flags &= ~EXFAT_ATTRIB_DIRTY; return 0; } static bool erase_entry(struct exfat* ef, struct exfat_node* node) { cluster_t cluster = node->entry_cluster; off_t offset = node->entry_offset; int name_entries = DIV_ROUND_UP(utf16_length(node->name), EXFAT_ENAME_MAX); uint8_t entry_type; entry_type = EXFAT_ENTRY_FILE & ~EXFAT_ENTRY_VALID; if (exfat_pwrite(ef->dev, &entry_type, 1, co2o(ef, cluster, offset)) < 0) { exfat_error("failed to erase meta1 entry"); return false; } if (!next_entry(ef, node->parent, &cluster, &offset)) return false; entry_type = EXFAT_ENTRY_FILE_INFO & ~EXFAT_ENTRY_VALID; if (exfat_pwrite(ef->dev, &entry_type, 1, co2o(ef, cluster, offset)) < 0) { exfat_error("failed to erase meta2 entry"); return false; } while (name_entries--) { if (!next_entry(ef, node->parent, &cluster, &offset)) return false; entry_type = EXFAT_ENTRY_FILE_NAME & ~EXFAT_ENTRY_VALID; if (exfat_pwrite(ef->dev, &entry_type, 1, co2o(ef, cluster, offset)) < 0) { exfat_error("failed to erase name entry"); return false; } } return true; } static int shrink_directory(struct exfat* ef, struct exfat_node* dir, off_t deleted_offset) { const struct exfat_node* node; const struct exfat_node* last_node; uint64_t entries = 0; uint64_t new_size; if (!(dir->flags & EXFAT_ATTRIB_DIR)) exfat_bug("attempted to shrink a file"); if (!(dir->flags & EXFAT_ATTRIB_CACHED)) exfat_bug("attempted to shrink uncached directory"); for (last_node = node = dir->child; node; node = node->next) { if (deleted_offset < node->entry_offset) { /* there are other entries after the removed one, no way to shrink this directory */ return 0; } if (last_node->entry_offset < node->entry_offset) last_node = node; } if (last_node) { /* offset of the last entry */ entries += last_node->entry_offset / sizeof(struct exfat_entry); /* two subentries with meta info */ entries += 2; /* subentries with file name */ entries += DIV_ROUND_UP(utf16_length(last_node->name), EXFAT_ENAME_MAX); } new_size = DIV_ROUND_UP(entries * sizeof(struct exfat_entry), CLUSTER_SIZE(*ef->sb)) * CLUSTER_SIZE(*ef->sb); if (new_size == 0) /* directory always has at least 1 cluster */ new_size = CLUSTER_SIZE(*ef->sb); if (new_size == dir->size) return 0; return exfat_truncate(ef, dir, new_size, true); } static int delete(struct exfat* ef, struct exfat_node* node) { struct exfat_node* parent = node->parent; off_t deleted_offset = node->entry_offset; int rc; exfat_get_node(parent); if (!erase_entry(ef, node)) { exfat_put_node(ef, parent); return -EIO; } exfat_update_mtime(parent); tree_detach(node); rc = shrink_directory(ef, parent, deleted_offset); node->flags |= EXFAT_ATTRIB_UNLINKED; if (rc != 0) { exfat_flush_node(ef, parent); exfat_put_node(ef, parent); return rc; } rc = exfat_flush_node(ef, parent); exfat_put_node(ef, parent); return rc; } int exfat_unlink(struct exfat* ef, struct exfat_node* node) { if (node->flags & EXFAT_ATTRIB_DIR) return -EISDIR; return delete(ef, node); } int exfat_rmdir(struct exfat* ef, struct exfat_node* node) { int rc; if (!(node->flags & EXFAT_ATTRIB_DIR)) return -ENOTDIR; /* check that directory is empty */ rc = exfat_cache_directory(ef, node); if (rc != 0) return rc; if (node->child) return -ENOTEMPTY; return delete(ef, node); } static int grow_directory(struct exfat* ef, struct exfat_node* dir, uint64_t asize, uint32_t difference) { return exfat_truncate(ef, dir, DIV_ROUND_UP(asize + difference, CLUSTER_SIZE(*ef->sb)) * CLUSTER_SIZE(*ef->sb), true); } static int find_slot(struct exfat* ef, struct exfat_node* dir, cluster_t* cluster, off_t* offset, int subentries) { struct iterator it; int rc; const struct exfat_entry* entry; int contiguous = 0; rc = opendir(ef, dir, &it); if (rc != 0) return rc; for (;;) { if (contiguous == 0) { *cluster = it.cluster; *offset = it.offset; } entry = get_entry_ptr(ef, &it); if (entry->type & EXFAT_ENTRY_VALID) contiguous = 0; else contiguous++; if (contiguous == subentries) break; /* suitable slot is found */ if (it.offset + sizeof(struct exfat_entry) >= dir->size) { rc = grow_directory(ef, dir, dir->size, (subentries - contiguous) * sizeof(struct exfat_entry)); if (rc != 0) { closedir(&it); return rc; } } if (!fetch_next_entry(ef, dir, &it)) { closedir(&it); return -EIO; } } closedir(&it); return 0; } static int write_entry(struct exfat* ef, struct exfat_node* dir, const le16_t* name, cluster_t cluster, off_t offset, uint16_t attrib) { struct exfat_node* node; struct exfat_entry_meta1 meta1; struct exfat_entry_meta2 meta2; const size_t name_length = utf16_length(name); const int name_entries = DIV_ROUND_UP(name_length, EXFAT_ENAME_MAX); int i; node = allocate_node(); if (node == NULL) return -ENOMEM; node->entry_cluster = cluster; node->entry_offset = offset; memcpy(node->name, name, name_length * sizeof(le16_t)); memset(&meta1, 0, sizeof(meta1)); meta1.type = EXFAT_ENTRY_FILE; meta1.continuations = 1 + name_entries; meta1.attrib = cpu_to_le16(attrib); exfat_unix2exfat(time(NULL), &meta1.crdate, &meta1.crtime, &meta1.crtime_cs); meta1.adate = meta1.mdate = meta1.crdate; meta1.atime = meta1.mtime = meta1.crtime; meta1.mtime_cs = meta1.crtime_cs; /* there is no atime_cs */ memset(&meta2, 0, sizeof(meta2)); meta2.type = EXFAT_ENTRY_FILE_INFO; meta2.flags = EXFAT_FLAG_ALWAYS1; meta2.name_length = name_length; meta2.name_hash = exfat_calc_name_hash(ef, node->name); meta2.start_cluster = cpu_to_le32(EXFAT_CLUSTER_FREE); meta1.checksum = exfat_calc_checksum(&meta1, &meta2, node->name); if (exfat_pwrite(ef->dev, &meta1, sizeof(meta1), co2o(ef, cluster, offset)) < 0) { exfat_error("failed to write meta1 entry"); return -EIO; } if (!next_entry(ef, dir, &cluster, &offset)) return -EIO; if (exfat_pwrite(ef->dev, &meta2, sizeof(meta2), co2o(ef, cluster, offset)) < 0) { exfat_error("failed to write meta2 entry"); return -EIO; } for (i = 0; i < name_entries; i++) { struct exfat_entry_name name_entry = {EXFAT_ENTRY_FILE_NAME, 0}; memcpy(name_entry.name, node->name + i * EXFAT_ENAME_MAX, MIN(EXFAT_ENAME_MAX, EXFAT_NAME_MAX - i * EXFAT_ENAME_MAX) * sizeof(le16_t)); if (!next_entry(ef, dir, &cluster, &offset)) return -EIO; if (exfat_pwrite(ef->dev, &name_entry, sizeof(name_entry), co2o(ef, cluster, offset)) < 0) { exfat_error("failed to write name entry"); return -EIO; } } init_node_meta1(node, &meta1); init_node_meta2(node, &meta2); tree_attach(dir, node); exfat_update_mtime(dir); return 0; } static int create(struct exfat* ef, const char* path, uint16_t attrib) { struct exfat_node* dir; struct exfat_node* existing; cluster_t cluster = EXFAT_CLUSTER_BAD; off_t offset = -1; le16_t name[EXFAT_NAME_MAX + 1]; int rc; rc = exfat_split(ef, &dir, &existing, name, path); if (rc != 0) return rc; if (existing != NULL) { exfat_put_node(ef, existing); exfat_put_node(ef, dir); return -EEXIST; } rc = find_slot(ef, dir, &cluster, &offset, 2 + DIV_ROUND_UP(utf16_length(name), EXFAT_ENAME_MAX)); if (rc != 0) { exfat_put_node(ef, dir); return rc; } rc = write_entry(ef, dir, name, cluster, offset, attrib); if (rc != 0) { exfat_put_node(ef, dir); return rc; } rc = exfat_flush_node(ef, dir); exfat_put_node(ef, dir); return rc; } int exfat_mknod(struct exfat* ef, const char* path) { return create(ef, path, EXFAT_ATTRIB_ARCH); } int exfat_mkdir(struct exfat* ef, const char* path) { int rc; struct exfat_node* node; rc = create(ef, path, EXFAT_ATTRIB_ARCH | EXFAT_ATTRIB_DIR); if (rc != 0) return rc; rc = exfat_lookup(ef, &node, path); if (rc != 0) return 0; /* directories always have at least one cluster */ rc = exfat_truncate(ef, node, CLUSTER_SIZE(*ef->sb), true); if (rc != 0) { delete(ef, node); exfat_put_node(ef, node); return rc; } rc = exfat_flush_node(ef, node); if (rc != 0) { delete(ef, node); exfat_put_node(ef, node); return rc; } exfat_put_node(ef, node); return 0; } static int rename_entry(struct exfat* ef, struct exfat_node* dir, struct exfat_node* node, const le16_t* name, cluster_t new_cluster, off_t new_offset) { struct exfat_entry_meta1 meta1; struct exfat_entry_meta2 meta2; cluster_t old_cluster = node->entry_cluster; off_t old_offset = node->entry_offset; const size_t name_length = utf16_length(name); const int name_entries = DIV_ROUND_UP(name_length, EXFAT_ENAME_MAX); int i; if (exfat_pread(ef->dev, &meta1, sizeof(meta1), co2o(ef, old_cluster, old_offset)) < 0) { exfat_error("failed to read meta1 entry on rename"); return -EIO; } if (!next_entry(ef, node->parent, &old_cluster, &old_offset)) return -EIO; if (exfat_pread(ef->dev, &meta2, sizeof(meta2), co2o(ef, old_cluster, old_offset)) < 0) { exfat_error("failed to read meta2 entry on rename"); return -EIO; } meta1.continuations = 1 + name_entries; meta2.name_hash = exfat_calc_name_hash(ef, name); meta2.name_length = name_length; meta1.checksum = exfat_calc_checksum(&meta1, &meta2, name); if (!erase_entry(ef, node)) return -EIO; node->entry_cluster = new_cluster; node->entry_offset = new_offset; if (exfat_pwrite(ef->dev, &meta1, sizeof(meta1), co2o(ef, new_cluster, new_offset)) < 0) { exfat_error("failed to write meta1 entry on rename"); return -EIO; } if (!next_entry(ef, dir, &new_cluster, &new_offset)) return -EIO; if (exfat_pwrite(ef->dev, &meta2, sizeof(meta2), co2o(ef, new_cluster, new_offset)) < 0) { exfat_error("failed to write meta2 entry on rename"); return -EIO; } for (i = 0; i < name_entries; i++) { struct exfat_entry_name name_entry = {EXFAT_ENTRY_FILE_NAME, 0}; memcpy(name_entry.name, name + i * EXFAT_ENAME_MAX, EXFAT_ENAME_MAX * sizeof(le16_t)); if (!next_entry(ef, dir, &new_cluster, &new_offset)) return -EIO; if (exfat_pwrite(ef->dev, &name_entry, sizeof(name_entry), co2o(ef, new_cluster, new_offset)) < 0) { exfat_error("failed to write name entry on rename"); return -EIO; } } memcpy(node->name, name, (EXFAT_NAME_MAX + 1) * sizeof(le16_t)); tree_detach(node); tree_attach(dir, node); return 0; } int exfat_rename(struct exfat* ef, const char* old_path, const char* new_path) { struct exfat_node* node; struct exfat_node* existing; struct exfat_node* dir; cluster_t cluster = EXFAT_CLUSTER_BAD; off_t offset = -1; le16_t name[EXFAT_NAME_MAX + 1]; int rc; rc = exfat_lookup(ef, &node, old_path); if (rc != 0) return rc; rc = exfat_split(ef, &dir, &existing, name, new_path); if (rc != 0) { exfat_put_node(ef, node); return rc; } /* check that target is not a subdirectory of the source */ if (node->flags & EXFAT_ATTRIB_DIR) { struct exfat_node* p; for (p = dir; p; p = p->parent) if (node == p) { if (existing != NULL) exfat_put_node(ef, existing); exfat_put_node(ef, dir); exfat_put_node(ef, node); return -EINVAL; } } if (existing != NULL) { /* remove target if it's not the same node as source */ if (existing != node) { if (existing->flags & EXFAT_ATTRIB_DIR) { if (node->flags & EXFAT_ATTRIB_DIR) rc = exfat_rmdir(ef, existing); else rc = -ENOTDIR; } else { if (!(node->flags & EXFAT_ATTRIB_DIR)) rc = exfat_unlink(ef, existing); else rc = -EISDIR; } exfat_put_node(ef, existing); if (rc != 0) { exfat_put_node(ef, dir); exfat_put_node(ef, node); return rc; } } else exfat_put_node(ef, existing); } rc = find_slot(ef, dir, &cluster, &offset, 2 + DIV_ROUND_UP(utf16_length(name), EXFAT_ENAME_MAX)); if (rc != 0) { exfat_put_node(ef, dir); exfat_put_node(ef, node); return rc; } rc = rename_entry(ef, dir, node, name, cluster, offset); exfat_put_node(ef, dir); exfat_put_node(ef, node); return rc; } void exfat_utimes(struct exfat_node* node, const struct timespec tv[2]) { node->atime = tv[0].tv_sec; node->mtime = tv[1].tv_sec; node->flags |= EXFAT_ATTRIB_DIRTY; } void exfat_update_atime(struct exfat_node* node) { node->atime = time(NULL); node->flags |= EXFAT_ATTRIB_DIRTY; } void exfat_update_mtime(struct exfat_node* node) { node->mtime = time(NULL); node->flags |= EXFAT_ATTRIB_DIRTY; } const char* exfat_get_label(struct exfat* ef) { return ef->label; } static int find_label(struct exfat* ef, cluster_t* cluster, off_t* offset) { struct iterator it; int rc; rc = opendir(ef, ef->root, &it); if (rc != 0) return rc; for (;;) { if (it.offset >= ef->root->size) { closedir(&it); return -ENOENT; } if (get_entry_ptr(ef, &it)->type == EXFAT_ENTRY_LABEL) { *cluster = it.cluster; *offset = it.offset; closedir(&it); return 0; } if (!fetch_next_entry(ef, ef->root, &it)) { closedir(&it); return -EIO; } } } int exfat_set_label(struct exfat* ef, const char* label) { le16_t label_utf16[EXFAT_ENAME_MAX + 1]; int rc; cluster_t cluster; off_t offset; struct exfat_entry_label entry; memset(label_utf16, 0, sizeof(label_utf16)); rc = utf8_to_utf16(label_utf16, label, EXFAT_ENAME_MAX, strlen(label)); if (rc != 0) return rc; rc = find_label(ef, &cluster, &offset); if (rc == -ENOENT) rc = find_slot(ef, ef->root, &cluster, &offset, 1); if (rc != 0) return rc; entry.type = EXFAT_ENTRY_LABEL; entry.length = utf16_length(label_utf16); memcpy(entry.name, label_utf16, sizeof(entry.name)); if (entry.length == 0) entry.type ^= EXFAT_ENTRY_VALID; if (exfat_pwrite(ef->dev, &entry, sizeof(struct exfat_entry_label), co2o(ef, cluster, offset)) < 0) { exfat_error("failed to write label entry"); return -EIO; } strcpy(ef->label, label); return 0; } partclone-0.2.86/src/exfat/platform.h000066400000000000000000000037511262102574200175000ustar00rootroot00000000000000/* platform.h (14.05.13) OS-specific code (libc-specific in fact). Note that systems with the same kernel can use different libc implementations. Free exFAT implementation. Copyright (C) 2010-2014 Andrew Nayenko This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef PLATFORM_H_INCLUDED #define PLATFORM_H_INCLUDED #if defined(__GLIBC__) #include #include #define exfat_bswap16(x) bswap_16(x) #define exfat_bswap32(x) bswap_32(x) #define exfat_bswap64(x) bswap_64(x) #define EXFAT_BYTE_ORDER __BYTE_ORDER #define EXFAT_LITTLE_ENDIAN __LITTLE_ENDIAN #define EXFAT_BIG_ENDIAN __BIG_ENDIAN #elif defined(__APPLE__) #include #include #define exfat_bswap16(x) OSSwapInt16(x) #define exfat_bswap32(x) OSSwapInt32(x) #define exfat_bswap64(x) OSSwapInt64(x) #define EXFAT_BYTE_ORDER BYTE_ORDER #define EXFAT_LITTLE_ENDIAN LITTLE_ENDIAN #define EXFAT_BIG_ENDIAN BIG_ENDIAN #elif defined(__FreeBSD__) || defined(__DragonFlyBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) #include #define exfat_bswap16(x) bswap16(x) #define exfat_bswap32(x) bswap32(x) #define exfat_bswap64(x) bswap64(x) #define EXFAT_BYTE_ORDER _BYTE_ORDER #define EXFAT_LITTLE_ENDIAN _LITTLE_ENDIAN #define EXFAT_BIG_ENDIAN _BIG_ENDIAN #else #error Unknown platform #endif #endif /* ifndef PLATFORM_H_INCLUDED */ partclone-0.2.86/src/exfat/time.c000066400000000000000000000115231262102574200166010ustar00rootroot00000000000000/* time.c (03.02.12) exFAT file system implementation library. Free exFAT implementation. Copyright (C) 2010-2014 Andrew Nayenko This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "exfat.h" /* timezone offset from UTC in seconds; positive for western timezones, negative for eastern ones */ static long exfat_timezone; #define SEC_IN_MIN 60ll #define SEC_IN_HOUR (60 * SEC_IN_MIN) #define SEC_IN_DAY (24 * SEC_IN_HOUR) #define SEC_IN_YEAR (365 * SEC_IN_DAY) /* not leap year */ /* Unix epoch started at 0:00:00 UTC 1 January 1970 */ #define UNIX_EPOCH_YEAR 1970 /* exFAT epoch started at 0:00:00 UTC 1 January 1980 */ #define EXFAT_EPOCH_YEAR 1980 /* number of years from Unix epoch to exFAT epoch */ #define EPOCH_DIFF_YEAR (EXFAT_EPOCH_YEAR - UNIX_EPOCH_YEAR) /* number of days from Unix epoch to exFAT epoch (considering leap days) */ #define EPOCH_DIFF_DAYS (EPOCH_DIFF_YEAR * 365 + EPOCH_DIFF_YEAR / 4) /* number of seconds from Unix epoch to exFAT epoch (considering leap days) */ #define EPOCH_DIFF_SEC (EPOCH_DIFF_DAYS * SEC_IN_DAY) /* number of leap years passed from exFAT epoch to the specified year (excluding the specified year itself) */ #define LEAP_YEARS(year) ((EXFAT_EPOCH_YEAR + (year) - 1) / 4 \ - (EXFAT_EPOCH_YEAR - 1) / 4) /* checks whether the specified year is leap */ #define IS_LEAP_YEAR(year) ((EXFAT_EPOCH_YEAR + (year)) % 4 == 0) static const time_t days_in_year[] = { /* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */ 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; time_t exfat_exfat2unix(le16_t date, le16_t time, uint8_t centisec) { time_t unix_time = EPOCH_DIFF_SEC; uint16_t ndate = le16_to_cpu(date); uint16_t ntime = le16_to_cpu(time); uint16_t day = ndate & 0x1f; /* 5 bits, 1-31 */ uint16_t month = ndate >> 5 & 0xf; /* 4 bits, 1-12 */ uint16_t year = ndate >> 9; /* 7 bits, 1-127 (+1980) */ uint16_t twosec = ntime & 0x1f; /* 5 bits, 0-29 (2 sec granularity) */ uint16_t min = ntime >> 5 & 0x3f; /* 6 bits, 0-59 */ uint16_t hour = ntime >> 11; /* 5 bits, 0-23 */ if (day == 0 || month == 0 || month > 12) { exfat_error("bad date %u-%02hu-%02hu", year + EXFAT_EPOCH_YEAR, month, day); return 0; } if (hour > 23 || min > 59 || twosec > 29) { exfat_error("bad time %hu:%02hu:%02u", hour, min, twosec * 2); return 0; } if (centisec > 199) { exfat_error("bad centiseconds count %hhu", centisec); return 0; } /* every 4th year between 1904 and 2096 is leap */ unix_time += year * SEC_IN_YEAR + LEAP_YEARS(year) * SEC_IN_DAY; unix_time += days_in_year[month] * SEC_IN_DAY; /* if it's leap year and February has passed we should add 1 day */ if ((EXFAT_EPOCH_YEAR + year) % 4 == 0 && month > 2) unix_time += SEC_IN_DAY; unix_time += (day - 1) * SEC_IN_DAY; unix_time += hour * SEC_IN_HOUR; unix_time += min * SEC_IN_MIN; /* exFAT represents time with 2 sec granularity */ unix_time += twosec * 2; unix_time += centisec / 100; /* exFAT stores timestamps in local time, so we correct it to UTC */ unix_time += exfat_timezone; return unix_time; } void exfat_unix2exfat(time_t unix_time, le16_t* date, le16_t* time, uint8_t* centisec) { time_t shift = EPOCH_DIFF_SEC + exfat_timezone; uint16_t day, month, year; uint16_t twosec, min, hour; int days; int i; /* time before exFAT epoch cannot be represented */ if (unix_time < shift) unix_time = shift; unix_time -= shift; days = unix_time / SEC_IN_DAY; year = (4 * days) / (4 * 365 + 1); days -= year * 365 + LEAP_YEARS(year); month = 0; for (i = 1; i <= 12; i++) { int leap_day = (IS_LEAP_YEAR(year) && i == 2); int leap_sub = (IS_LEAP_YEAR(year) && i >= 3); if (i == 12 || days - leap_sub < days_in_year[i + 1] + leap_day) { month = i; days -= days_in_year[i] + leap_sub; break; } } day = days + 1; hour = (unix_time % SEC_IN_DAY) / SEC_IN_HOUR; min = (unix_time % SEC_IN_HOUR) / SEC_IN_MIN; twosec = (unix_time % SEC_IN_MIN) / 2; *date = cpu_to_le16(day | (month << 5) | (year << 9)); *time = cpu_to_le16(twosec | (min << 5) | (hour << 11)); if (centisec) *centisec = (unix_time % 2) * 100; } void exfat_tzset(void) { time_t now; tzset(); now = time(NULL); exfat_timezone = mktime(gmtime(&now)) - now; } partclone-0.2.86/src/exfat/utf.c000066400000000000000000000127171262102574200164470ustar00rootroot00000000000000/* utf.c (13.09.09) exFAT file system implementation library. Free exFAT implementation. Copyright (C) 2010-2014 Andrew Nayenko This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "exfat.h" #include static char* wchar_to_utf8(char* output, wchar_t wc, size_t outsize) { if (wc <= 0x7f) { if (outsize < 1) return NULL; *output++ = (char) wc; } else if (wc <= 0x7ff) { if (outsize < 2) return NULL; *output++ = 0xc0 | (wc >> 6); *output++ = 0x80 | (wc & 0x3f); } else if (wc <= 0xffff) { if (outsize < 3) return NULL; *output++ = 0xe0 | (wc >> 12); *output++ = 0x80 | ((wc >> 6) & 0x3f); *output++ = 0x80 | (wc & 0x3f); } else if (wc <= 0x1fffff) { if (outsize < 4) return NULL; *output++ = 0xf0 | (wc >> 18); *output++ = 0x80 | ((wc >> 12) & 0x3f); *output++ = 0x80 | ((wc >> 6) & 0x3f); *output++ = 0x80 | (wc & 0x3f); } else if (wc <= 0x3ffffff) { if (outsize < 5) return NULL; *output++ = 0xf8 | (wc >> 24); *output++ = 0x80 | ((wc >> 18) & 0x3f); *output++ = 0x80 | ((wc >> 12) & 0x3f); *output++ = 0x80 | ((wc >> 6) & 0x3f); *output++ = 0x80 | (wc & 0x3f); } else if (wc <= 0x7fffffff) { if (outsize < 6) return NULL; *output++ = 0xfc | (wc >> 30); *output++ = 0x80 | ((wc >> 24) & 0x3f); *output++ = 0x80 | ((wc >> 18) & 0x3f); *output++ = 0x80 | ((wc >> 12) & 0x3f); *output++ = 0x80 | ((wc >> 6) & 0x3f); *output++ = 0x80 | (wc & 0x3f); } else return NULL; return output; } static const le16_t* utf16_to_wchar(const le16_t* input, wchar_t* wc, size_t insize) { if ((le16_to_cpu(input[0]) & 0xfc00) == 0xd800) { if (insize < 2 || (le16_to_cpu(input[1]) & 0xfc00) != 0xdc00) return NULL; *wc = ((wchar_t) (le16_to_cpu(input[0]) & 0x3ff) << 10); *wc |= (le16_to_cpu(input[1]) & 0x3ff); *wc += 0x10000; return input + 2; } else { *wc = le16_to_cpu(*input); return input + 1; } } int utf16_to_utf8(char* output, const le16_t* input, size_t outsize, size_t insize) { const le16_t* inp = input; char* outp = output; wchar_t wc; while (inp - input < insize && le16_to_cpu(*inp)) { inp = utf16_to_wchar(inp, &wc, insize - (inp - input)); if (inp == NULL) { exfat_error("illegal UTF-16 sequence"); return -EILSEQ; } outp = wchar_to_utf8(outp, wc, outsize - (outp - output)); if (outp == NULL) { exfat_error("name is too long"); return -ENAMETOOLONG; } } *outp = '\0'; return 0; } static const char* utf8_to_wchar(const char* input, wchar_t* wc, size_t insize) { if ((input[0] & 0x80) == 0 && insize >= 1) { *wc = (wchar_t) input[0]; return input + 1; } if ((input[0] & 0xe0) == 0xc0 && insize >= 2) { *wc = (((wchar_t) input[0] & 0x1f) << 6) | ((wchar_t) input[1] & 0x3f); return input + 2; } if ((input[0] & 0xf0) == 0xe0 && insize >= 3) { *wc = (((wchar_t) input[0] & 0x0f) << 12) | (((wchar_t) input[1] & 0x3f) << 6) | ((wchar_t) input[2] & 0x3f); return input + 3; } if ((input[0] & 0xf8) == 0xf0 && insize >= 4) { *wc = (((wchar_t) input[0] & 0x07) << 18) | (((wchar_t) input[1] & 0x3f) << 12) | (((wchar_t) input[2] & 0x3f) << 6) | ((wchar_t) input[3] & 0x3f); return input + 4; } if ((input[0] & 0xfc) == 0xf8 && insize >= 5) { *wc = (((wchar_t) input[0] & 0x03) << 24) | (((wchar_t) input[1] & 0x3f) << 18) | (((wchar_t) input[2] & 0x3f) << 12) | (((wchar_t) input[3] & 0x3f) << 6) | ((wchar_t) input[4] & 0x3f); return input + 5; } if ((input[0] & 0xfe) == 0xfc && insize >= 6) { *wc = (((wchar_t) input[0] & 0x01) << 30) | (((wchar_t) input[1] & 0x3f) << 24) | (((wchar_t) input[2] & 0x3f) << 18) | (((wchar_t) input[3] & 0x3f) << 12) | (((wchar_t) input[4] & 0x3f) << 6) | ((wchar_t) input[5] & 0x3f); return input + 6; } return NULL; } static le16_t* wchar_to_utf16(le16_t* output, wchar_t wc, size_t outsize) { if (wc <= 0xffff) /* if character is from BMP */ { if (outsize == 0) return NULL; output[0] = cpu_to_le16(wc); return output + 1; } if (outsize < 2) return NULL; wc -= 0x10000; output[0] = cpu_to_le16(0xd800 | ((wc >> 10) & 0x3ff)); output[1] = cpu_to_le16(0xdc00 | (wc & 0x3ff)); return output + 2; } int utf8_to_utf16(le16_t* output, const char* input, size_t outsize, size_t insize) { const char* inp = input; le16_t* outp = output; wchar_t wc; while (inp - input < insize && *inp) { inp = utf8_to_wchar(inp, &wc, insize - (inp - input)); if (inp == NULL) { exfat_error("illegal UTF-8 sequence"); return -EILSEQ; } outp = wchar_to_utf16(outp, wc, outsize - (outp - output)); if (outp == NULL) { exfat_error("name is too long"); return -ENAMETOOLONG; } } *outp = cpu_to_le16(0); return 0; } size_t utf16_length(const le16_t* str) { size_t i = 0; while (le16_to_cpu(str[i])) i++; return i; } partclone-0.2.86/src/exfat/utils.c000066400000000000000000000123361262102574200170060ustar00rootroot00000000000000/* utils.c (04.09.09) exFAT file system implementation library. Free exFAT implementation. Copyright (C) 2010-2014 Andrew Nayenko This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "exfat.h" #include #include #include void exfat_stat(const struct exfat* ef, const struct exfat_node* node, struct stat* stbuf) { memset(stbuf, 0, sizeof(struct stat)); if (node->flags & EXFAT_ATTRIB_DIR) stbuf->st_mode = S_IFDIR | (0777 & ~ef->dmask); else stbuf->st_mode = S_IFREG | (0777 & ~ef->fmask); stbuf->st_nlink = 1; stbuf->st_uid = ef->uid; stbuf->st_gid = ef->gid; stbuf->st_size = node->size; stbuf->st_blocks = DIV_ROUND_UP(node->size, CLUSTER_SIZE(*ef->sb)) * CLUSTER_SIZE(*ef->sb) / 512; stbuf->st_mtime = node->mtime; stbuf->st_atime = node->atime; /* set ctime to mtime to ensure we don't break programs that rely on ctime (e.g. rsync) */ stbuf->st_ctime = node->mtime; } void exfat_get_name(const struct exfat_node* node, char* buffer, size_t n) { if (utf16_to_utf8(buffer, node->name, n, EXFAT_NAME_MAX) != 0) exfat_bug("failed to convert name to UTF-8"); } uint16_t exfat_start_checksum(const struct exfat_entry_meta1* entry) { uint16_t sum = 0; int i; for (i = 0; i < sizeof(struct exfat_entry); i++) if (i != 2 && i != 3) /* skip checksum field itself */ sum = ((sum << 15) | (sum >> 1)) + ((const uint8_t*) entry)[i]; return sum; } uint16_t exfat_add_checksum(const void* entry, uint16_t sum) { int i; for (i = 0; i < sizeof(struct exfat_entry); i++) sum = ((sum << 15) | (sum >> 1)) + ((const uint8_t*) entry)[i]; return sum; } le16_t exfat_calc_checksum(const struct exfat_entry_meta1* meta1, const struct exfat_entry_meta2* meta2, const le16_t* name) { uint16_t checksum; const int name_entries = DIV_ROUND_UP(utf16_length(name), EXFAT_ENAME_MAX); int i; checksum = exfat_start_checksum(meta1); checksum = exfat_add_checksum(meta2, checksum); for (i = 0; i < name_entries; i++) { struct exfat_entry_name name_entry = {EXFAT_ENTRY_FILE_NAME, 0}; memcpy(name_entry.name, name + i * EXFAT_ENAME_MAX, MIN(EXFAT_ENAME_MAX, EXFAT_NAME_MAX - i * EXFAT_ENAME_MAX) * sizeof(le16_t)); checksum = exfat_add_checksum(&name_entry, checksum); } return cpu_to_le16(checksum); } uint32_t exfat_vbr_start_checksum(const void* sector, size_t size) { size_t i; uint32_t sum = 0; for (i = 0; i < size; i++) /* skip volume_state and allocated_percent fields */ if (i != 0x6a && i != 0x6b && i != 0x70) sum = ((sum << 31) | (sum >> 1)) + ((const uint8_t*) sector)[i]; return sum; } uint32_t exfat_vbr_add_checksum(const void* sector, size_t size, uint32_t sum) { size_t i; for (i = 0; i < size; i++) sum = ((sum << 31) | (sum >> 1)) + ((const uint8_t*) sector)[i]; return sum; } le16_t exfat_calc_name_hash(const struct exfat* ef, const le16_t* name) { size_t i; size_t length = utf16_length(name); uint16_t hash = 0; for (i = 0; i < length; i++) { uint16_t c = le16_to_cpu(name[i]); /* convert to upper case */ if (c < ef->upcase_chars) c = le16_to_cpu(ef->upcase[c]); hash = ((hash << 15) | (hash >> 1)) + (c & 0xff); hash = ((hash << 15) | (hash >> 1)) + (c >> 8); } return cpu_to_le16(hash); } void exfat_humanize_bytes(uint64_t value, struct exfat_human_bytes* hb) { size_t i; /* 16 EB (minus 1 byte) is the largest size that can be represented by uint64_t */ const char* units[] = {"bytes", "KB", "MB", "GB", "TB", "PB", "EB"}; uint64_t divisor = 1; uint64_t temp = 0; for (i = 0; ; i++, divisor *= 1024) { temp = (value + divisor / 2) / divisor; if (temp == 0) break; if (temp / 1024 * 1024 == temp) continue; if (temp < 10240) break; } hb->value = temp; hb->unit = units[i]; } void exfat_print_info(const struct exfat_super_block* sb, uint32_t free_clusters) { struct exfat_human_bytes hb; off_t total_space = le64_to_cpu(sb->sector_count) * SECTOR_SIZE(*sb); off_t avail_space = (off_t) free_clusters * CLUSTER_SIZE(*sb); printf("File system version %hhu.%hhu\n", sb->version.major, sb->version.minor); exfat_humanize_bytes(SECTOR_SIZE(*sb), &hb); printf("Sector size %10"PRIu64" %s\n", hb.value, hb.unit); exfat_humanize_bytes(CLUSTER_SIZE(*sb), &hb); printf("Cluster size %10"PRIu64" %s\n", hb.value, hb.unit); exfat_humanize_bytes(total_space, &hb); printf("Volume size %10"PRIu64" %s\n", hb.value, hb.unit); exfat_humanize_bytes(total_space - avail_space, &hb); printf("Used space %10"PRIu64" %s\n", hb.value, hb.unit); exfat_humanize_bytes(avail_space, &hb); printf("Available space %10"PRIu64" %s\n", hb.value, hb.unit); } partclone-0.2.86/src/exfat/version.h000066400000000000000000000017441262102574200173410ustar00rootroot00000000000000/* version.h (12.06.10) Version constants. Free exFAT implementation. Copyright (C) 2010-2014 Andrew Nayenko This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef VERSION_H_INCLUDED #define VERSION_H_INCLUDED #define EXFAT_VERSION_MAJOR 1 #define EXFAT_VERSION_MINOR 1 #define EXFAT_VERSION_PATCH 0 #endif /* ifndef VERSION_H_INCLUDED */ partclone-0.2.86/src/exfatclone.c000066400000000000000000000055211262102574200166650ustar00rootroot00000000000000/** * exfatclone.c - part of Partclone project * * Copyright (c) 2007~ Thomas Tsai * * read exfat super block and bitmap * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ #include #include #include #include #include #include "exfat/exfat.h" #include "partclone.h" #include "exfatclone.h" #include "progress.h" #include "fs_common.h" #define EXFAT_SECTOR_SIZE(sb) (1 << (sb).sector_bits) char *EXECNAME = "partclone.exfat"; extern fs_cmd_opt fs_opt; struct exfat ef; /// open device static void fs_open(char* device){ log_mesg(2, 0, 0, fs_opt.debug, "%s: exfat_mount\n", __FILE__); if (exfat_mount(&ef, device, "ro") != 0) log_mesg(0, 1, 1, fs_opt.debug, "%s: File system exfat open fail\n", __FILE__); log_mesg(2, 0, 0, fs_opt.debug, "%s: exfat_mount done\n", __FILE__); } /// close device static void fs_close(){ log_mesg(2, 0, 0, fs_opt.debug, "%s: exfat_umount\n", __FILE__); exfat_unmount(&ef); log_mesg(2, 0, 0, fs_opt.debug, "%s: exfat_umount done\n", __FILE__); } /// readbitmap - read bitmap extern void readbitmap(char* device, image_head image_hdr, unsigned long* bitmap, int pui) { off_t a = 0, b = 0; off_t block = 0;; int start = 0; int bit_size = 1; fs_open(device); /// init progress progress_bar prog; /// progress_bar structure defined in progress.h progress_init(&prog, start, image_hdr.totalblock, image_hdr.totalblock, BITMAP, bit_size); while (exfat_find_used_sectors(&ef, &a, &b) == 0){ printf("block %" PRId64 " %" PRId64 " \n", a, b); for (block = a; block <= b; block++){ pc_set_bit((uint64_t)block, bitmap); log_mesg(3, 0, 0, fs_opt.debug, "%s: used block %" PRId64 " \n", __FILE__, block); /// update progress update_pui(&prog, block, block, 0); } } fs_close(); /// update progress update_pui(&prog, 1, 1, 1); } /// read super block and write to image head extern void initial_image_hdr(char* device, image_head* image_hdr) { struct exfat_super_block* sb; uint64_t free_sectors, free_clusters; fs_open(device); free_clusters = exfat_count_free_clusters(&ef); free_sectors = (uint64_t) free_clusters << ef.sb->spc_bits; sb = ef.sb; strncpy(image_hdr->magic, IMAGE_MAGIC, IMAGE_MAGIC_SIZE); strncpy(image_hdr->fs, exfat_MAGIC, FS_MAGIC_SIZE); image_hdr->block_size = EXFAT_SECTOR_SIZE(*sb); image_hdr->totalblock = le64_to_cpu(sb->sector_count); image_hdr->usedblocks = (le64_to_cpu(sb->sector_count) - free_sectors); image_hdr->device_size = (image_hdr->totalblock*image_hdr->block_size); fs_close(); } partclone-0.2.86/src/exfatclone.h000066400000000000000000000012141262102574200166650ustar00rootroot00000000000000/** * reiserfsclone.h - part of Partclone project * * Copyright (c) 2007~ Thomas Tsai * * read reiserfs super block and bitmap * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ /// readbitmap - read bitmap extern void readbitmap(char* device, image_head image_hdr, unsigned long* bitmap, int pui); /// read super block and write to image head extern void initial_image_hdr(char* device, image_head* image_hdr); partclone-0.2.86/src/extfsclone.c000066400000000000000000000202311262102574200167020ustar00rootroot00000000000000/** * extfsclone.h - part of Partclone project * * Copyright (c) 2007~ Thomas Tsai * * read ext2/3 super block and bitmap * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ #include #include #include #include #include #include #include #include #include #include #include #define in_use(m, x) (ext2fs_test_bit ((x), (m))) #include "partclone.h" #include "extfsclone.h" #include "progress.h" #include "fs_common.h" ext2_filsys fs; char *EXECNAME = "partclone.extfs"; extern fs_cmd_opt fs_opt; /// open device static void fs_open(char* device){ errcode_t retval; int use_superblock = 0; int use_blocksize = 0; int flags; flags = EXT2_FLAG_JOURNAL_DEV_OK | EXT2_FLAG_SOFTSUPP_FEATURES | EXT2_FLAG_64BITS; if (use_superblock && !use_blocksize) { for (use_blocksize = EXT2_MIN_BLOCK_SIZE; use_blocksize <= EXT2_MAX_BLOCK_SIZE; use_blocksize *= 2) { retval = ext2fs_open (device, flags, use_superblock, use_blocksize, unix_io_manager, &fs); if (!retval) break; } } else retval = ext2fs_open (device, flags, use_superblock, use_blocksize, unix_io_manager, &fs); if (retval) log_mesg(0, 1, 1, fs_opt.debug, "%s: Couldn't find valid filesystem superblock.\n", __FILE__); ext2fs_mark_valid(fs); if(fs_opt.ignore_fschk){ log_mesg(1, 0, 0, fs_opt.debug, "%s: Ignore filesystem check\n", __FILE__); } else { if ((fs->super->s_state & EXT2_ERROR_FS) || !ext2fs_test_valid(fs)) log_mesg(0, 1, 1, fs_opt.debug, "%s: FS contains a file system with errors\n", __FILE__); else if ((fs->super->s_state & EXT2_VALID_FS) == 0) log_mesg(0, 1, 1, fs_opt.debug, "%s: FS was not cleanly unmounted\n", __FILE__); else if ((fs->super->s_max_mnt_count > 0) && (fs->super->s_mnt_count >= (unsigned) fs->super->s_max_mnt_count)) { log_mesg(0, 1, 1, fs_opt.debug, "%s: FS has been mounted %"PRIu16" times without being checked\n", __FILE__, fs->super->s_mnt_count); } } } /// close device static void fs_close(){ ext2fs_close(fs); } /// get block size from super block static int block_size(){ return EXT2_BLOCK_SIZE(fs->super); } /// get total block from super block static unsigned long long block_count(){ return (unsigned long long)ext2fs_blocks_count(fs->super); } /// get used blocks ( total - free ) from super block static unsigned long long get_used_blocks(){ return (unsigned long long)(ext2fs_blocks_count(fs->super) - ext2fs_free_blocks_count(fs->super)); } /// readbitmap - cread and heck bitmap, reference dumpe2fs extern void readbitmap(char* device, image_head image_hdr, unsigned long* bitmap, int pui){ errcode_t retval; unsigned long group; unsigned long long current_block, block; unsigned long long free, gfree; char *block_bitmap=NULL; int block_nbytes; unsigned long long blk_itr; int bg_flags = 0; int start = 0; int bit_size = 1; int B_UN_INIT = 0; int ext4_gfree_mismatch = 0; log_mesg(2, 0, 0, fs_opt.debug, "%s: readbitmap %p\n", __FILE__, bitmap); fs_open(device); retval = ext2fs_read_bitmaps(fs); /// open extfs bitmap if (retval) log_mesg(0, 1, 1, fs_opt.debug, "%s: Couldn't find valid filesystem bitmap.\n", __FILE__); block_nbytes = EXT2_BLOCKS_PER_GROUP(fs->super) / 8; if (fs->block_map) block_bitmap = malloc(block_nbytes); /// initial image bitmap as 1 (all block are used) memset(bitmap, 0xFF, sizeof(unsigned long)*LONGS(image_hdr.totalblock)); free = 0; current_block = 0; blk_itr = fs->super->s_first_data_block; /// init progress progress_bar prog; /// progress_bar structure defined in progress.h progress_init(&prog, start, image_hdr.totalblock, image_hdr.totalblock, BITMAP, bit_size); /// each group for (group = 0; group < fs->group_desc_count; group++) { gfree = 0; B_UN_INIT = 0; if (block_bitmap) { ext2fs_get_block_bitmap_range2(fs->block_map, blk_itr, block_nbytes << 3, block_bitmap); if (fs->super->s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_GDT_CSUM){ #ifdef EXTFS_1_41 bg_flags = fs->group_desc[group].bg_flags; #else bg_flags = ext2fs_bg_flags(fs, group); #endif if (bg_flags&EXT2_BG_BLOCK_UNINIT){ log_mesg(1, 0, 0, fs_opt.debug, "%s: BLOCK_UNINIT for group %lu\n", __FILE__, group); B_UN_INIT = 1; } else { log_mesg(2, 0, 0, fs_opt.debug, "%s: BLOCK_INIT for group %lu\n", __FILE__, group); } } /// each block in group for (block = 0; ((block < fs->super->s_blocks_per_group) && (current_block < (image_hdr.totalblock-1))); block++) { current_block = block + blk_itr; if (in_use (block_bitmap, block)){ pc_set_bit(current_block, bitmap); log_mesg(3, 0, 0, fs_opt.debug, "%s: used block %llu at group %lu\n", __FILE__, current_block, group); } else { free++; gfree++; pc_clear_bit(current_block, bitmap); log_mesg(3, 0, 0, fs_opt.debug, "%s: free block %llu at group %lu init %i\n", __FILE__, current_block, group, (int)B_UN_INIT); } /// update progress update_pui(&prog, current_block, current_block, 0);//keep update } blk_itr += fs->super->s_blocks_per_group; } log_mesg(2, 0, 0, fs_opt.debug, "%s: free bitmap (gfree = %lli, bg_blocks_count = %lli)at %lu group.\n", __FILE__, gfree, ext2fs_bg_free_blocks_count(fs, group), group); /// check free blocks in group #ifdef EXTFS_1_41 if (gfree != fs->group_desc[group].bg_free_blocks_count){ #else if (gfree != ext2fs_bg_free_blocks_count(fs, group)){ #endif if (!B_UN_INIT) log_mesg(0, 1, 1, fs_opt.debug, "%s: bitmap error at %lu group.\n", __FILE__, group); else ext4_gfree_mismatch = 1; } } /// check all free blocks in partition if (free != ext2fs_free_blocks_count(fs->super)) { if ((fs->super->s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_GDT_CSUM) && (ext4_gfree_mismatch)) log_mesg(1, 0, 0, fs_opt.debug, "%s: EXT4 bitmap metadata mismatch\n", __FILE__); else log_mesg(0, 1, 1, fs_opt.debug, "%s: bitmap free count err, partclone get free:%llu but extfs get %llu\n", __FILE__, free, ext2fs_free_blocks_count(fs->super)); } fs_close(); /// update progress update_pui(&prog, 1, 1, 1);//finish } /// get extfs type static int test_extfs_type(char* device){ int ext2 = 1; int ext3 = 2; int ext4 = 3; fs_open(device); if(fs->super->s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_GDT_CSUM){ log_mesg(1, 0, 0, fs_opt.debug, "%s: test feature as EXT4\n", __FILE__); return ext4; } else if (fs->super->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL){ log_mesg(1, 0, 0, fs_opt.debug, "%s: test feature as EXT3\n", __FILE__); return ext3; } else { log_mesg(1, 0, 0, fs_opt.debug, "%s: test feature as EXT2\n", __FILE__); return ext2; } fs_close(); return 0; } /// read super block and write to image head extern void initial_image_hdr(char* device, image_head* image_hdr) { int fs_type = 0; fs_type = test_extfs_type(device); log_mesg(1, 0, 0, fs_opt.debug, "%s: extfs version is %i\n", __FILE__, fs_type); strncpy(image_hdr->magic, IMAGE_MAGIC, IMAGE_MAGIC_SIZE); strncpy(image_hdr->fs, extfs_MAGIC, FS_MAGIC_SIZE); fs_open(device); image_hdr->block_size = (int)block_size(); image_hdr->totalblock = (unsigned long long)block_count(); image_hdr->usedblocks = (unsigned long long)get_used_blocks(); image_hdr->device_size = (unsigned long long)(image_hdr->block_size * image_hdr->totalblock); log_mesg(1, 0, 0, fs_opt.debug, "%s: extfs block_size %i\n", __FILE__, image_hdr->block_size); log_mesg(1, 0, 0, fs_opt.debug, "%s: extfs total block %lli\n", __FILE__, image_hdr->totalblock); log_mesg(1, 0, 0, fs_opt.debug, "%s: extfs used blocks %lli\n", __FILE__, image_hdr->usedblocks); log_mesg(1, 0, 0, fs_opt.debug, "%s: extfs device size %lli\n", __FILE__, image_hdr->device_size); fs_close(); } partclone-0.2.86/src/extfsclone.h000066400000000000000000000012431262102574200167110ustar00rootroot00000000000000/** * extfsclone.h - part of Partclone project * * Copyright (c) 2007~ Thomas Tsai * * read exfat super block and bitmap * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ /// readbitmap - cread and heck bitmap, reference dumpe2fs extern void readbitmap(char* device, image_head image_hdr, unsigned long* bitmap, int pui); /// read super block and write to image head extern void initial_image_hdr(char* device, image_head* image_hdr); partclone-0.2.86/src/f2fs/000077500000000000000000000000001262102574200152265ustar00rootroot00000000000000partclone-0.2.86/src/f2fs/clone.c000066400000000000000000000046761262102574200165070ustar00rootroot00000000000000/** * main.c * * Copyright (c) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.com/ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ #include "fsck.h" #include struct f2fs_fsck gfsck = { .sbi.fsck = &gfsck, }; extern struct f2fs_configuration config; void dump_sit(struct f2fs_sb_info *sbi) { DBG(0, "start dump sit\n"); struct f2fs_fsck *fsck = F2FS_FSCK(sbi); DBG(0, "start fsck sit\n"); u32 blk = 0; for ( blk = 4096 ; blk <= 131071 ; blk++ ){ DBG(0, "blk = %i\n", blk); if (f2fs_test_bit(BLKOFF_FROM_MAIN(sbi, blk), fsck->sit_area_bitmap) == 0x0) { DBG(0, "test SIT bitmap is 0x0. blk_addr[0x%x] %i\n", blk, blk); }else{ DBG(0, "test SIT bitmap is 0x1. blk_addr[0x%x] %i\n", blk, blk); } if (f2fs_test_bit(BLKOFF_FROM_MAIN(sbi, blk), fsck->main_area_bitmap) == 0x0) { DBG(0, "test main bitmap is 0x0. blk_addr[0x%x] %i\n", blk, blk); }else{ DBG(0, "test main bitmap is 0x1. blk_addr[0x%x] %i\n", blk, blk); } } } int do_fsck(struct f2fs_sb_info *sbi) { int ret; ret = fsck_init(sbi); if (ret < 0) return ret; fsck_chk_orphan_node(sbi); struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); struct f2fs_checkpoint *cp = F2FS_CKPT(sbi); DBG(0, "display sb\n"); DBG(0, "sb block_count %i\n", sb->block_count); DBG(0, "sb root ino %i\n", sb->root_ino); DBG(0, "sb block_size %i\n", F2FS_BLKSIZE); DBG(0, "device size %i\n", config.total_sectors*config.sector_size); DBG(0, "free_seg %i\n", cp->free_segment_count); DBG(0, "user_block_count %i\n", cp->user_block_count); DBG(0, "segment_count %i\n", sb->segment_count); DBG(0, "free_segment_count %i\n", cp->free_segment_count); DBG(0, "DEFAULT_BLOCKS_PER_SEGMENT %i\n", DEFAULT_BLOCKS_PER_SEGMENT); dump_sit(sbi); //ret = fsck_verify(sbi); fsck_free(sbi); return ret; } int main (int argc, char **argv) { struct f2fs_sb_info *sbi = &gfsck.sbi; int ret = 0; f2fs_init_configuration(&config); config.device_name = argv[optind]; if (f2fs_dev_is_umounted(&config) < 0) return -1; /* Get device */ if (f2fs_get_device_info(&config) < 0) return -1; if (f2fs_do_mount(sbi) < 0) return -1; ret = do_fsck(sbi); f2fs_do_umount(sbi); printf("\nDone.\n"); return ret; } partclone-0.2.86/src/f2fs/f2fs.h000066400000000000000000000250401262102574200162400ustar00rootroot00000000000000/** * f2fs.h * * Copyright (c) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.com/ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ #ifndef _F2FS_H_ #define _F2FS_H_ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "list.h" #include "f2fs_fs.h" #define EXIT_ERR_CODE (-1) #define ver_after(a, b) (typecheck(unsigned long long, a) && \ typecheck(unsigned long long, b) && \ ((long long)((a) - (b)) > 0)) enum { NAT_BITMAP, SIT_BITMAP }; struct node_info { nid_t nid; nid_t ino; u32 blk_addr; unsigned char version; }; struct f2fs_nm_info { block_t nat_blkaddr; nid_t max_nid; nid_t init_scan_nid; nid_t next_scan_nid; unsigned int nat_cnt; unsigned int fcnt; char *nat_bitmap; int bitmap_size; }; struct seg_entry { unsigned short valid_blocks; /* # of valid blocks */ unsigned char *cur_valid_map; /* validity bitmap of blocks */ /* * # of valid blocks and the validity bitmap stored in the the last * checkpoint pack. This information is used by the SSR mode. */ unsigned short ckpt_valid_blocks; unsigned char *ckpt_valid_map; unsigned char type; /* segment type like CURSEG_XXX_TYPE */ unsigned long long mtime; /* modification time of the segment */ }; struct sec_entry { unsigned int valid_blocks; /* # of valid blocks in a section */ }; struct sit_info { block_t sit_base_addr; /* start block address of SIT area */ block_t sit_blocks; /* # of blocks used by SIT area */ block_t written_valid_blocks; /* # of valid blocks in main area */ char *sit_bitmap; /* SIT bitmap pointer */ unsigned int bitmap_size; /* SIT bitmap size */ unsigned long *dirty_sentries_bitmap; /* bitmap for dirty sentries */ unsigned int dirty_sentries; /* # of dirty sentries */ unsigned int sents_per_block; /* # of SIT entries per block */ struct seg_entry *sentries; /* SIT segment-level cache */ struct sec_entry *sec_entries; /* SIT section-level cache */ unsigned long long elapsed_time; /* elapsed time after mount */ unsigned long long mounted_time; /* mount time */ unsigned long long min_mtime; /* min. modification time */ unsigned long long max_mtime; /* max. modification time */ }; struct curseg_info { struct f2fs_summary_block *sum_blk; /* cached summary block */ unsigned char alloc_type; /* current allocation type */ unsigned int segno; /* current segment number */ unsigned short next_blkoff; /* next block offset to write */ unsigned int zone; /* current zone number */ unsigned int next_segno; /* preallocated segment */ }; struct f2fs_sm_info { struct sit_info *sit_info; struct curseg_info *curseg_array; block_t seg0_blkaddr; block_t main_blkaddr; block_t ssa_blkaddr; unsigned int segment_count; unsigned int main_segments; unsigned int reserved_segments; unsigned int ovp_segments; }; struct f2fs_sb_info { struct f2fs_fsck *fsck; struct f2fs_super_block *raw_super; struct f2fs_nm_info *nm_info; struct f2fs_sm_info *sm_info; struct f2fs_checkpoint *ckpt; struct list_head orphan_inode_list; unsigned int n_orphans; /* basic file system units */ unsigned int log_sectors_per_block; /* log2 sectors per block */ unsigned int log_blocksize; /* log2 block size */ unsigned int blocksize; /* block size */ unsigned int root_ino_num; /* root inode number*/ unsigned int node_ino_num; /* node inode number*/ unsigned int meta_ino_num; /* meta inode number*/ unsigned int log_blocks_per_seg; /* log2 blocks per segment */ unsigned int blocks_per_seg; /* blocks per segment */ unsigned int segs_per_sec; /* segments per section */ unsigned int secs_per_zone; /* sections per zone */ unsigned int total_sections; /* total section count */ unsigned int total_node_count; /* total node block count */ unsigned int total_valid_node_count; /* valid node block count */ unsigned int total_valid_inode_count; /* valid inode count */ int active_logs; /* # of active logs */ block_t user_block_count; /* # of user blocks */ block_t total_valid_block_count; /* # of valid blocks */ block_t alloc_valid_block_count; /* # of allocated blocks */ block_t last_valid_block_count; /* for recovery */ u32 s_next_generation; /* for NFS support */ unsigned int cur_victim_sec; /* current victim section num */ }; static inline struct f2fs_super_block *F2FS_RAW_SUPER(struct f2fs_sb_info *sbi) { return (struct f2fs_super_block *)(sbi->raw_super); } static inline struct f2fs_checkpoint *F2FS_CKPT(struct f2fs_sb_info *sbi) { return (struct f2fs_checkpoint *)(sbi->ckpt); } static inline struct f2fs_fsck *F2FS_FSCK(struct f2fs_sb_info *sbi) { return (struct f2fs_fsck *)(sbi->fsck); } static inline struct f2fs_nm_info *NM_I(struct f2fs_sb_info *sbi) { return (struct f2fs_nm_info *)(sbi->nm_info); } static inline struct f2fs_sm_info *SM_I(struct f2fs_sb_info *sbi) { return (struct f2fs_sm_info *)(sbi->sm_info); } static inline struct sit_info *SIT_I(struct f2fs_sb_info *sbi) { return (struct sit_info *)(SM_I(sbi)->sit_info); } static inline unsigned long __bitmap_size(struct f2fs_sb_info *sbi, int flag) { struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); /* return NAT or SIT bitmap */ if (flag == NAT_BITMAP) return le32_to_cpu(ckpt->nat_ver_bitmap_bytesize); else if (flag == SIT_BITMAP) return le32_to_cpu(ckpt->sit_ver_bitmap_bytesize); return 0; } static inline void *__bitmap_ptr(struct f2fs_sb_info *sbi, int flag) { struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); int offset = (flag == NAT_BITMAP) ? le32_to_cpu(ckpt->sit_ver_bitmap_bytesize) : 0; return &ckpt->sit_nat_version_bitmap + offset; } static inline bool is_set_ckpt_flags(struct f2fs_checkpoint *cp, unsigned int f) { unsigned int ckpt_flags = le32_to_cpu(cp->ckpt_flags); return ckpt_flags & f; } static inline block_t __start_cp_addr(struct f2fs_sb_info *sbi) { block_t start_addr; struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); unsigned long long ckpt_version = le64_to_cpu(ckpt->checkpoint_ver); start_addr = le32_to_cpu(F2FS_RAW_SUPER(sbi)->cp_blkaddr); /* * odd numbered checkpoint should at cp segment 0 * and even segent must be at cp segment 1 */ if (!(ckpt_version & 1)) start_addr += sbi->blocks_per_seg; return start_addr; } static inline block_t __start_sum_addr(struct f2fs_sb_info *sbi) { return le32_to_cpu(F2FS_CKPT(sbi)->cp_pack_start_sum); } #define GET_ZONENO_FROM_SEGNO(sbi, segno) \ ((segno / sbi->segs_per_sec) / sbi->secs_per_zone) #define IS_DATASEG(t) \ ((t == CURSEG_HOT_DATA) || (t == CURSEG_COLD_DATA) || \ (t == CURSEG_WARM_DATA)) #define IS_NODESEG(t) \ ((t == CURSEG_HOT_NODE) || (t == CURSEG_COLD_NODE) || \ (t == CURSEG_WARM_NODE)) #define GET_SUM_BLKADDR(sbi, segno) \ ((sbi->sm_info->ssa_blkaddr) + segno) #define GET_SEGOFF_FROM_SEG0(sbi, blk_addr) \ ((blk_addr) - SM_I(sbi)->seg0_blkaddr) #define GET_SEGNO_FROM_SEG0(sbi, blk_addr) \ (GET_SEGOFF_FROM_SEG0(sbi, blk_addr) >> sbi->log_blocks_per_seg) #define FREE_I_START_SEGNO(sbi) GET_SEGNO_FROM_SEG0(sbi, SM_I(sbi)->main_blkaddr) #define GET_R2L_SEGNO(sbi, segno) (segno + FREE_I_START_SEGNO(sbi)) #define START_BLOCK(sbi, segno) (SM_I(sbi)->main_blkaddr + (segno << sbi->log_blocks_per_seg)) static inline struct curseg_info *CURSEG_I(struct f2fs_sb_info *sbi, int type) { return (struct curseg_info *)(SM_I(sbi)->curseg_array + type); } static inline block_t start_sum_block(struct f2fs_sb_info *sbi) { return __start_cp_addr(sbi) + le32_to_cpu(F2FS_CKPT(sbi)->cp_pack_start_sum); } static inline block_t sum_blk_addr(struct f2fs_sb_info *sbi, int base, int type) { return __start_cp_addr(sbi) + le32_to_cpu(F2FS_CKPT(sbi)->cp_pack_total_block_count) - (base + 1) + type; } #define nats_in_cursum(sum) (le16_to_cpu(sum->n_nats)) #define sits_in_cursum(sum) (le16_to_cpu(sum->n_sits)) #define nat_in_journal(sum, i) (sum->nat_j.entries[i].ne) #define nid_in_journal(sum, i) (sum->nat_j.entries[i].nid) #define sit_in_journal(sum, i) (sum->sit_j.entries[i].se) #define segno_in_journal(sum, i) (sum->sit_j.entries[i].segno) #define SIT_ENTRY_OFFSET(sit_i, segno) \ (segno % sit_i->sents_per_block) #define SIT_BLOCK_OFFSET(sit_i, segno) \ (segno / SIT_ENTRY_PER_BLOCK) #define TOTAL_SEGS(sbi) (SM_I(sbi)->main_segments) #define IS_VALID_NID(sbi, nid) \ do { \ ASSERT(nid <= (NAT_ENTRY_PER_BLOCK * \ F2FS_RAW_SUPER(sbi)->segment_count_nat \ << (sbi->log_blocks_per_seg - 1))); \ } while (0); #define IS_VALID_BLK_ADDR(sbi, addr) \ do { \ if (addr >= F2FS_RAW_SUPER(sbi)->block_count || \ addr < SM_I(sbi)->main_blkaddr) \ { \ DBG(0, "block addr [0x%x]\n", addr); \ ASSERT(addr < F2FS_RAW_SUPER(sbi)->block_count); \ ASSERT(addr >= SM_I(sbi)->main_blkaddr); \ } \ } while (0); static inline u64 BLKOFF_FROM_MAIN(struct f2fs_sb_info *sbi, u64 blk_addr) { ASSERT(blk_addr >= SM_I(sbi)->main_blkaddr); return blk_addr - SM_I(sbi)->main_blkaddr; } static inline u32 GET_SEGNO(struct f2fs_sb_info *sbi, u64 blk_addr) { return (u32)(BLKOFF_FROM_MAIN(sbi, blk_addr) >> sbi->log_blocks_per_seg); } static inline u32 OFFSET_IN_SEG(struct f2fs_sb_info *sbi, u64 blk_addr) { return (u32)(BLKOFF_FROM_MAIN(sbi, blk_addr) % (1 << sbi->log_blocks_per_seg)); } static inline void node_info_from_raw_nat(struct node_info *ni, struct f2fs_nat_entry *raw_nat) { ni->ino = le32_to_cpu(raw_nat->ino); ni->blk_addr = le32_to_cpu(raw_nat->block_addr); ni->version = raw_nat->version; } extern int lookup_nat_in_journal(struct f2fs_sb_info *sbi, u32 nid, struct f2fs_nat_entry *ne); #define IS_SUM_NODE_SEG(footer) (footer.entry_type == SUM_TYPE_NODE) #endif /* _F2FS_H_ */ partclone-0.2.86/src/f2fs/f2fs_fs.h000066400000000000000000000502541262102574200167350ustar00rootroot00000000000000/** * f2fs_fs.h * * Copyright (c) 2012 Samsung Electronics Co., Ltd. * http://www.samsung.com/ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ #ifndef __F2FS_FS_H__ #define __F2FS_FS_H__ #include #include #include #include #include #ifdef HAVE_CONFIG_H #include #endif typedef u_int64_t u64; typedef u_int32_t u32; typedef u_int16_t u16; typedef u_int8_t u8; typedef u32 block_t; typedef u32 nid_t; typedef u8 bool; typedef unsigned long pgoff_t; #if __BYTE_ORDER == __LITTLE_ENDIAN #define le16_to_cpu(x) ((__u16)(x)) #define le32_to_cpu(x) ((__u32)(x)) #define le64_to_cpu(x) ((__u64)(x)) #define cpu_to_le16(x) ((__u16)(x)) #define cpu_to_le32(x) ((__u32)(x)) #define cpu_to_le64(x) ((__u64)(x)) #elif __BYTE_ORDER == __BIG_ENDIAN #define le16_to_cpu(x) bswap_16(x) #define le32_to_cpu(x) bswap_32(x) #define le64_to_cpu(x) bswap_64(x) #define cpu_to_le16(x) bswap_16(x) #define cpu_to_le32(x) bswap_32(x) #define cpu_to_le64(x) bswap_64(x) #endif #define typecheck(type,x) \ ({ type __dummy; \ typeof(x) __dummy2; \ (void)(&__dummy == &__dummy2); \ 1; \ }) #define NULL_SEGNO ((unsigned int)~0) /* * Debugging interfaces */ #define ASSERT_MSG(exp, fmt, ...) \ do { \ if (!(exp)) { \ printf("\nAssertion failed!\n"); \ printf("[%s:%4d] " #exp, __func__, __LINE__); \ printf("\n --> "fmt, ##__VA_ARGS__); \ exit(-1); \ } \ } while (0); #define ASSERT(exp) \ do { \ if (!(exp)) { \ printf("\nAssertion failed!\n"); \ printf("[%s:%4d] " #exp"\n", __func__, __LINE__);\ exit(-1); \ } \ } while (0); #define ERR_MSG(fmt, ...) \ do { \ printf("[%s:%d] " fmt, __func__, __LINE__, ##__VA_ARGS__); \ } while (0); #define MSG(n, fmt, ...) \ do { \ if (config.dbg_lv >= n) { \ printf(fmt, ##__VA_ARGS__); \ } \ } while (0); #define DBG(n, fmt, ...) \ do { \ if (config.dbg_lv >= n) { \ printf("[%s:%4d] " fmt, \ __func__, __LINE__, ##__VA_ARGS__); \ } \ } while (0); /* Display on console */ #define DISP(fmt, ptr, member) \ do { \ printf("%-30s" fmt, #member, ((ptr)->member)); \ } while (0); #define DISP_u32(ptr, member) \ do { \ assert(sizeof((ptr)->member) <= 4); \ printf("%-30s" "\t\t[0x%8x : %u]\n", \ #member, ((ptr)->member), ((ptr)->member) ); \ } while (0); #define DISP_u64(ptr, member) \ do { \ assert(sizeof((ptr)->member) == 8); \ printf("%-30s" "\t\t[0x%8llx : %llu]\n", \ #member, ((ptr)->member), ((ptr)->member) ); \ } while (0); #define DISP_utf(ptr, member) \ do { \ printf("%-30s" "\t\t[%s]\n", #member, ((ptr)->member) ); \ } while (0); /* Display to buffer */ #define BUF_DISP_u32(buf, data, len, ptr, member) \ do { \ assert(sizeof((ptr)->member) <= 4); \ snprintf(buf, len, #member); \ snprintf(data, len, "0x%x : %u", ((ptr)->member), ((ptr)->member)); \ } while (0); #define BUF_DISP_u64(buf, data, len, ptr, member) \ do { \ assert(sizeof((ptr)->member) == 8); \ snprintf(buf, len, #member); \ snprintf(data, len, "0x%llx : %llu", ((ptr)->member), ((ptr)->member)); \ } while (0); #define BUF_DISP_utf(buf, data, len, ptr, member) \ do { \ snprintf(buf, len, #member); \ } while (0); /* these are defined in kernel */ #define PAGE_SIZE 4096 #define PAGE_CACHE_SIZE 4096 #define BITS_PER_BYTE 8 #define F2FS_SUPER_MAGIC 0xF2F52010 /* F2FS Magic Number */ #define CHECKSUM_OFFSET 4092 /* for mkfs */ #define F2FS_MIN_VOLUME_SIZE 104857600 #define F2FS_NUMBER_OF_CHECKPOINT_PACK 2 #define DEFAULT_SECTOR_SIZE 512 #define DEFAULT_SECTORS_PER_BLOCK 8 #define DEFAULT_BLOCKS_PER_SEGMENT 512 #define DEFAULT_SEGMENTS_PER_SECTION 1 enum f2fs_config_func { FSCK, DUMP, }; struct f2fs_configuration { u_int32_t sector_size; u_int32_t reserved_segments; u_int32_t overprovision; u_int32_t cur_seg[6]; u_int32_t segs_per_sec; u_int32_t secs_per_zone; u_int32_t start_sector; u_int64_t total_sectors; u_int32_t sectors_per_blk; u_int32_t blks_per_seg; char *vol_label; int heap; int32_t fd; char *device_name; char *extension_list; int dbg_lv; int trim; int func; void *private; } __attribute__((packed)); #ifdef CONFIG_64BIT #define BITS_PER_LONG 64 #else #define BITS_PER_LONG 32 #endif #define BIT_MASK(nr) (1 << (nr % BITS_PER_LONG)) #define BIT_WORD(nr) (nr / BITS_PER_LONG) /* * Copied from fs/f2fs/f2fs.h */ #define NR_CURSEG_DATA_TYPE (3) #define NR_CURSEG_NODE_TYPE (3) #define NR_CURSEG_TYPE (NR_CURSEG_DATA_TYPE + NR_CURSEG_NODE_TYPE) enum { CURSEG_HOT_DATA = 0, /* directory entry blocks */ CURSEG_WARM_DATA, /* data blocks */ CURSEG_COLD_DATA, /* multimedia or GCed data blocks */ CURSEG_HOT_NODE, /* direct node blocks of directory files */ CURSEG_WARM_NODE, /* direct node blocks of normal files */ CURSEG_COLD_NODE, /* indirect node blocks */ NO_CHECK_TYPE }; /* * Copied from fs/f2fs/segment.h */ #define GET_SUM_TYPE(footer) ((footer)->entry_type) #define SET_SUM_TYPE(footer, type) ((footer)->entry_type = type) /* * Copied from include/linux/f2fs_sb.h */ #define F2FS_SUPER_OFFSET 1024 /* byte-size offset */ #define F2FS_LOG_SECTOR_SIZE 9 /* 9 bits for 512 byte */ #define F2FS_LOG_SECTORS_PER_BLOCK 3 /* 4KB: F2FS_BLKSIZE */ #define F2FS_BLKSIZE 4096 /* support only 4KB block */ #define F2FS_MAX_EXTENSION 64 /* # of extension entries */ #define NULL_ADDR 0x0U #define NEW_ADDR -1U #define F2FS_ROOT_INO(sbi) (sbi->root_ino_num) #define F2FS_NODE_INO(sbi) (sbi->node_ino_num) #define F2FS_META_INO(sbi) (sbi->meta_ino_num) /* This flag is used by node and meta inodes, and by recovery */ #define GFP_F2FS_ZERO (GFP_NOFS | __GFP_ZERO) /* * For further optimization on multi-head logs, on-disk layout supports maximum * 16 logs by default. The number, 16, is expected to cover all the cases * enoughly. The implementaion currently uses no more than 6 logs. * Half the logs are used for nodes, and the other half are used for data. */ #define MAX_ACTIVE_LOGS 16 #define MAX_ACTIVE_NODE_LOGS 8 #define MAX_ACTIVE_DATA_LOGS 8 /* * For superblock */ struct f2fs_super_block { __le32 magic; /* Magic Number */ __le16 major_ver; /* Major Version */ __le16 minor_ver; /* Minor Version */ __le32 log_sectorsize; /* log2 sector size in bytes */ __le32 log_sectors_per_block; /* log2 # of sectors per block */ __le32 log_blocksize; /* log2 block size in bytes */ __le32 log_blocks_per_seg; /* log2 # of blocks per segment */ __le32 segs_per_sec; /* # of segments per section */ __le32 secs_per_zone; /* # of sections per zone */ __le32 checksum_offset; /* checksum offset inside super block */ __le64 block_count; /* total # of user blocks */ __le32 section_count; /* total # of sections */ __le32 segment_count; /* total # of segments */ __le32 segment_count_ckpt; /* # of segments for checkpoint */ __le32 segment_count_sit; /* # of segments for SIT */ __le32 segment_count_nat; /* # of segments for NAT */ __le32 segment_count_ssa; /* # of segments for SSA */ __le32 segment_count_main; /* # of segments for main area */ __le32 segment0_blkaddr; /* start block address of segment 0 */ __le32 cp_blkaddr; /* start block address of checkpoint */ __le32 sit_blkaddr; /* start block address of SIT */ __le32 nat_blkaddr; /* start block address of NAT */ __le32 ssa_blkaddr; /* start block address of SSA */ __le32 main_blkaddr; /* start block address of main area */ __le32 root_ino; /* root inode number */ __le32 node_ino; /* node inode number */ __le32 meta_ino; /* meta inode number */ __u8 uuid[16]; /* 128-bit uuid for volume */ __le16 volume_name[512]; /* volume name */ __le32 extension_count; /* # of extensions below */ __u8 extension_list[F2FS_MAX_EXTENSION][8]; /* extension array */ } __attribute__((packed)); /* * For checkpoint */ #define CP_ERROR_FLAG 0x00000008 #define CP_COMPACT_SUM_FLAG 0x00000004 #define CP_ORPHAN_PRESENT_FLAG 0x00000002 #define CP_UMOUNT_FLAG 0x00000001 struct f2fs_checkpoint { __le64 checkpoint_ver; /* checkpoint block version number */ __le64 user_block_count; /* # of user blocks */ __le64 valid_block_count; /* # of valid blocks in main area */ __le32 rsvd_segment_count; /* # of reserved segments for gc */ __le32 overprov_segment_count; /* # of overprovision segments */ __le32 free_segment_count; /* # of free segments in main area */ /* information of current node segments */ __le32 cur_node_segno[MAX_ACTIVE_NODE_LOGS]; __le16 cur_node_blkoff[MAX_ACTIVE_NODE_LOGS]; /* information of current data segments */ __le32 cur_data_segno[MAX_ACTIVE_DATA_LOGS]; __le16 cur_data_blkoff[MAX_ACTIVE_DATA_LOGS]; __le32 ckpt_flags; /* Flags : umount and journal_present */ __le32 cp_pack_total_block_count; /* total # of one cp pack */ __le32 cp_pack_start_sum; /* start block number of data summary */ __le32 valid_node_count; /* Total number of valid nodes */ __le32 valid_inode_count; /* Total number of valid inodes */ __le32 next_free_nid; /* Next free node number */ __le32 sit_ver_bitmap_bytesize; /* Default value 64 */ __le32 nat_ver_bitmap_bytesize; /* Default value 256 */ __le32 checksum_offset; /* checksum offset inside cp block */ __le64 elapsed_time; /* mounted time */ /* allocation type of current segment */ unsigned char alloc_type[MAX_ACTIVE_LOGS]; /* SIT and NAT version bitmap */ unsigned char sit_nat_version_bitmap[1]; } __attribute__((packed)); /* * For orphan inode management */ #define F2FS_ORPHANS_PER_BLOCK 1020 struct f2fs_orphan_block { __le32 ino[F2FS_ORPHANS_PER_BLOCK]; /* inode numbers */ __le32 reserved; /* reserved */ __le16 blk_addr; /* block index in current CP */ __le16 blk_count; /* Number of orphan inode blocks in CP */ __le32 entry_count; /* Total number of orphan nodes in current CP */ __le32 check_sum; /* CRC32 for orphan inode block */ } __attribute__((packed)); /* * For NODE structure */ struct f2fs_extent { __le32 fofs; /* start file offset of the extent */ __le32 blk_addr; /* start block address of the extent */ __le32 len; /* lengh of the extent */ } __attribute__((packed)); #define F2FS_NAME_LEN 255 #define F2FS_INLINE_XATTR_ADDRS 50 /* 200 bytes for inline xattrs */ #define DEF_ADDRS_PER_INODE 923 /* Address Pointers in an Inode */ #define ADDRS_PER_INODE(fi) addrs_per_inode(fi) #define ADDRS_PER_BLOCK 1018 /* Address Pointers in a Direct Block */ #define NIDS_PER_BLOCK 1018 /* Node IDs in an Indirect Block */ #define NODE_DIR1_BLOCK (DEF_ADDRS_PER_INODE + 1) #define NODE_DIR2_BLOCK (DEF_ADDRS_PER_INODE + 2) #define NODE_IND1_BLOCK (DEF_ADDRS_PER_INODE + 3) #define NODE_IND2_BLOCK (DEF_ADDRS_PER_INODE + 4) #define NODE_DIND_BLOCK (DEF_ADDRS_PER_INODE + 5) #define F2FS_INLINE_XATTR 0x01 /* file inline xattr flag */ #define F2FS_INLINE_DATA 0x02 /* file inline data flag */ #define MAX_INLINE_DATA (sizeof(__le32) * (DEF_ADDRS_PER_INODE - \ F2FS_INLINE_XATTR_ADDRS - 1)) #define INLINE_DATA_OFFSET (PAGE_CACHE_SIZE - sizeof(struct node_footer) \ - sizeof(__le32)*(DEF_ADDRS_PER_INODE + 5 - 1)) struct f2fs_inode { __le16 i_mode; /* file mode */ __u8 i_advise; /* file hints */ __u8 i_inline; /* file inline flags */ __le32 i_uid; /* user ID */ __le32 i_gid; /* group ID */ __le32 i_links; /* links count */ __le64 i_size; /* file size in bytes */ __le64 i_blocks; /* file size in blocks */ __le64 i_atime; /* access time */ __le64 i_ctime; /* change time */ __le64 i_mtime; /* modification time */ __le32 i_atime_nsec; /* access time in nano scale */ __le32 i_ctime_nsec; /* change time in nano scale */ __le32 i_mtime_nsec; /* modification time in nano scale */ __le32 i_generation; /* file version (for NFS) */ __le32 i_current_depth; /* only for directory depth */ __le32 i_xattr_nid; /* nid to save xattr */ __le32 i_flags; /* file attributes */ __le32 i_pino; /* parent inode number */ __le32 i_namelen; /* file name length */ __u8 i_name[F2FS_NAME_LEN]; /* file name for SPOR */ __u8 i_reserved2; /* for backward compatibility */ struct f2fs_extent i_ext; /* caching a largest extent */ __le32 i_addr[DEF_ADDRS_PER_INODE]; /* Pointers to data blocks */ __le32 i_nid[5]; /* direct(2), indirect(2), double_indirect(1) node id */ } __attribute__((packed)); struct direct_node { __le32 addr[ADDRS_PER_BLOCK]; /* array of data block address */ } __attribute__((packed)); struct indirect_node { __le32 nid[NIDS_PER_BLOCK]; /* array of data block address */ } __attribute__((packed)); enum { COLD_BIT_SHIFT = 0, FSYNC_BIT_SHIFT, DENT_BIT_SHIFT, OFFSET_BIT_SHIFT }; struct node_footer { __le32 nid; /* node id */ __le32 ino; /* inode nunmber */ __le32 flag; /* include cold/fsync/dentry marks and offset */ __le64 cp_ver; /* checkpoint version */ __le32 next_blkaddr; /* next node page block address */ } __attribute__((packed)); struct f2fs_node { /* can be one of three types: inode, direct, and indirect types */ union { struct f2fs_inode i; struct direct_node dn; struct indirect_node in; }; struct node_footer footer; } __attribute__((packed)); /* * For NAT entries */ #define NAT_ENTRY_PER_BLOCK (PAGE_CACHE_SIZE / sizeof(struct f2fs_nat_entry)) struct f2fs_nat_entry { __u8 version; /* latest version of cached nat entry */ __le32 ino; /* inode number */ __le32 block_addr; /* block address */ } __attribute__((packed)); struct f2fs_nat_block { struct f2fs_nat_entry entries[NAT_ENTRY_PER_BLOCK]; } __attribute__((packed)); /* * For SIT entries * * Each segment is 2MB in size by default so that a bitmap for validity of * there-in blocks should occupy 64 bytes, 512 bits. * Not allow to change this. */ #define SIT_VBLOCK_MAP_SIZE 64 #define SIT_ENTRY_PER_BLOCK (PAGE_CACHE_SIZE / sizeof(struct f2fs_sit_entry)) /* * Note that f2fs_sit_entry->vblocks has the following bit-field information. * [15:10] : allocation type such as CURSEG_XXXX_TYPE * [9:0] : valid block count */ #define SIT_VBLOCKS_SHIFT 10 #define SIT_VBLOCKS_MASK ((1 << SIT_VBLOCKS_SHIFT) - 1) #define GET_SIT_VBLOCKS(raw_sit) \ (le16_to_cpu((raw_sit)->vblocks) & SIT_VBLOCKS_MASK) #define GET_SIT_TYPE(raw_sit) \ ((le16_to_cpu((raw_sit)->vblocks) & ~SIT_VBLOCKS_MASK) \ >> SIT_VBLOCKS_SHIFT) struct f2fs_sit_entry { __le16 vblocks; /* reference above */ __u8 valid_map[SIT_VBLOCK_MAP_SIZE]; /* bitmap for valid blocks */ __le64 mtime; /* segment age for cleaning */ } __attribute__((packed)); struct f2fs_sit_block { struct f2fs_sit_entry entries[SIT_ENTRY_PER_BLOCK]; } __attribute__((packed)); /* * For segment summary * * One summary block contains exactly 512 summary entries, which represents * exactly 2MB segment by default. Not allow to change the basic units. * * NOTE: For initializing fields, you must use set_summary * * - If data page, nid represents dnode's nid * - If node page, nid represents the node page's nid. * * The ofs_in_node is used by only data page. It represents offset * from node's page's beginning to get a data block address. * ex) data_blkaddr = (block_t)(nodepage_start_address + ofs_in_node) */ #define ENTRIES_IN_SUM 512 #define SUMMARY_SIZE (7) /* sizeof(struct summary) */ #define SUM_FOOTER_SIZE (5) /* sizeof(struct summary_footer) */ #define SUM_ENTRIES_SIZE (SUMMARY_SIZE * ENTRIES_IN_SUM) /* a summary entry for a 4KB-sized block in a segment */ struct f2fs_summary { __le32 nid; /* parent node id */ union { __u8 reserved[3]; struct { __u8 version; /* node version number */ __le16 ofs_in_node; /* block index in parent node */ } __attribute__((packed)); }; } __attribute__((packed)); /* summary block type, node or data, is stored to the summary_footer */ #define SUM_TYPE_NODE (1) #define SUM_TYPE_DATA (0) struct summary_footer { unsigned char entry_type; /* SUM_TYPE_XXX */ __u32 check_sum; /* summary checksum */ } __attribute__((packed)); #define SUM_JOURNAL_SIZE (F2FS_BLKSIZE - SUM_FOOTER_SIZE -\ SUM_ENTRIES_SIZE) #define NAT_JOURNAL_ENTRIES ((SUM_JOURNAL_SIZE - 2) /\ sizeof(struct nat_journal_entry)) #define NAT_JOURNAL_RESERVED ((SUM_JOURNAL_SIZE - 2) %\ sizeof(struct nat_journal_entry)) #define SIT_JOURNAL_ENTRIES ((SUM_JOURNAL_SIZE - 2) /\ sizeof(struct sit_journal_entry)) #define SIT_JOURNAL_RESERVED ((SUM_JOURNAL_SIZE - 2) %\ sizeof(struct sit_journal_entry)) /* * frequently updated NAT/SIT entries can be stored in the spare area in * summary blocks */ enum { NAT_JOURNAL = 0, SIT_JOURNAL }; struct nat_journal_entry { __le32 nid; struct f2fs_nat_entry ne; } __attribute__((packed)); struct nat_journal { struct nat_journal_entry entries[NAT_JOURNAL_ENTRIES]; __u8 reserved[NAT_JOURNAL_RESERVED]; } __attribute__((packed)); struct sit_journal_entry { __le32 segno; struct f2fs_sit_entry se; } __attribute__((packed)); struct sit_journal { struct sit_journal_entry entries[SIT_JOURNAL_ENTRIES]; __u8 reserved[SIT_JOURNAL_RESERVED]; } __attribute__((packed)); /* 4KB-sized summary block structure */ struct f2fs_summary_block { struct f2fs_summary entries[ENTRIES_IN_SUM]; union { __le16 n_nats; __le16 n_sits; }; /* spare area is used by NAT or SIT journals */ union { struct nat_journal nat_j; struct sit_journal sit_j; }; struct summary_footer footer; } __attribute__((packed)); /* * For directory operations */ #define F2FS_DOT_HASH 0 #define F2FS_DDOT_HASH F2FS_DOT_HASH #define F2FS_MAX_HASH (~((0x3ULL) << 62)) #define F2FS_HASH_COL_BIT ((0x1ULL) << 63) typedef __le32 f2fs_hash_t; /* One directory entry slot covers 8bytes-long file name */ #define F2FS_SLOT_LEN 8 #define F2FS_SLOT_LEN_BITS 3 #define GET_DENTRY_SLOTS(x) ((x + F2FS_SLOT_LEN - 1) >> F2FS_SLOT_LEN_BITS) /* the number of dentry in a block */ #define NR_DENTRY_IN_BLOCK 214 /* MAX level for dir lookup */ #define MAX_DIR_HASH_DEPTH 63 #define SIZE_OF_DIR_ENTRY 11 /* by byte */ #define SIZE_OF_DENTRY_BITMAP ((NR_DENTRY_IN_BLOCK + BITS_PER_BYTE - 1) / \ BITS_PER_BYTE) #define SIZE_OF_RESERVED (PAGE_SIZE - ((SIZE_OF_DIR_ENTRY + \ F2FS_SLOT_LEN) * \ NR_DENTRY_IN_BLOCK + SIZE_OF_DENTRY_BITMAP)) /* One directory entry slot representing F2FS_SLOT_LEN-sized file name */ struct f2fs_dir_entry { __le32 hash_code; /* hash code of file name */ __le32 ino; /* inode number */ __le16 name_len; /* lengh of file name */ __u8 file_type; /* file type */ } __attribute__((packed)); /* 4KB-sized directory entry block */ struct f2fs_dentry_block { /* validity bitmap for directory entries in each block */ __u8 dentry_bitmap[SIZE_OF_DENTRY_BITMAP]; __u8 reserved[SIZE_OF_RESERVED]; struct f2fs_dir_entry dentry[NR_DENTRY_IN_BLOCK]; __u8 filename[NR_DENTRY_IN_BLOCK][F2FS_SLOT_LEN]; } __attribute__((packed)); /* file types used in inode_info->flags */ enum FILE_TYPE { F2FS_FT_UNKNOWN, F2FS_FT_REG_FILE, F2FS_FT_DIR, F2FS_FT_CHRDEV, F2FS_FT_BLKDEV, F2FS_FT_FIFO, F2FS_FT_SOCK, F2FS_FT_SYMLINK, F2FS_FT_MAX, /* added for fsck */ F2FS_FT_ORPHAN, }; /* from f2fs/segment.h */ enum { LFS = 0, SSR }; extern void ASCIIToUNICODE(u_int16_t *, u_int8_t *); extern int log_base_2(u_int32_t); extern unsigned int addrs_per_inode(struct f2fs_inode *); extern int get_bits_in_byte(unsigned char n); extern int set_bit(unsigned int nr,void * addr); extern int clear_bit(unsigned int nr, void * addr); extern int test_bit(unsigned int nr, const void * addr); extern int f2fs_test_bit(unsigned int, const char *); extern int f2fs_set_bit(unsigned int, char *); extern int f2fs_clear_bit(unsigned int, char *); extern unsigned long find_next_bit(const unsigned long *, unsigned long, unsigned long); extern u_int32_t f2fs_cal_crc32(u_int32_t, void *, int); extern int f2fs_crc_valid(u_int32_t blk_crc, void *buf, int len); extern void f2fs_init_configuration(struct f2fs_configuration *); extern int f2fs_dev_is_umounted(struct f2fs_configuration *); extern int f2fs_get_device_info(struct f2fs_configuration *); extern int dev_read(void *, __u64, size_t); extern int dev_write(void *, __u64, size_t); extern int dev_read_block(void *, __u64); extern int dev_read_blocks(void *, __u64, __u32 ); f2fs_hash_t f2fs_dentry_hash(const char *, int); extern struct f2fs_configuration config; #endif /*__F2FS_FS_H */ partclone-0.2.86/src/f2fs/fsck.c000066400000000000000000000513631262102574200163300ustar00rootroot00000000000000/** * fsck.c * * Copyright (c) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.com/ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ #include "fsck.h" char *tree_mark; int tree_mark_size = 256; static int add_into_hard_link_list(struct f2fs_sb_info *sbi, u32 nid, u32 link_cnt) { struct f2fs_fsck *fsck = F2FS_FSCK(sbi); struct hard_link_node *node = NULL, *tmp = NULL, *prev = NULL; node = calloc(sizeof(struct hard_link_node), 1); ASSERT(node != NULL); node->nid = nid; node->links = link_cnt; node->next = NULL; if (fsck->hard_link_list_head == NULL) { fsck->hard_link_list_head = node; goto out; } tmp = fsck->hard_link_list_head; /* Find insertion position */ while (tmp && (nid < tmp->nid)) { ASSERT(tmp->nid != nid); prev = tmp; tmp = tmp->next; } if (tmp == fsck->hard_link_list_head) { node->next = tmp; fsck->hard_link_list_head = node; } else { prev->next = node; node->next = tmp; } out: DBG(2, "ino[0x%x] has hard links [0x%x]\n", nid, link_cnt); return 0; } static int find_and_dec_hard_link_list(struct f2fs_sb_info *sbi, u32 nid) { struct f2fs_fsck *fsck = F2FS_FSCK(sbi); struct hard_link_node *node = NULL, *prev = NULL; if (fsck->hard_link_list_head == NULL) { ASSERT(0); return -1; } node = fsck->hard_link_list_head; while (node && (nid < node->nid)) { prev = node; node = node->next; } if (node == NULL || (nid != node->nid)) { ASSERT(0); return -1; } /* Decrease link count */ node->links = node->links - 1; /* if link count becomes one, remove the node */ if (node->links == 1) { if (fsck->hard_link_list_head == node) fsck->hard_link_list_head = node->next; else prev->next = node->next; free(node); } return 0; } static int is_valid_ssa_node_blk(struct f2fs_sb_info *sbi, u32 nid, u32 blk_addr) { int ret = 0; struct f2fs_summary sum_entry; ret = get_sum_entry(sbi, blk_addr, &sum_entry); ASSERT(ret >= 0); if (ret == SEG_TYPE_DATA || ret == SEG_TYPE_CUR_DATA) { ASSERT_MSG(0, "Summary footer is not a node segment summary\n");; } else if (ret == SEG_TYPE_NODE) { if (le32_to_cpu(sum_entry.nid) != nid) { DBG(0, "nid [0x%x]\n", nid); DBG(0, "target blk_addr [0x%x]\n", blk_addr); DBG(0, "summary blk_addr [0x%x]\n", GET_SUM_BLKADDR(sbi, GET_SEGNO(sbi, blk_addr))); DBG(0, "seg no / offset [0x%x / 0x%x]\n", GET_SEGNO(sbi, blk_addr), OFFSET_IN_SEG(sbi, blk_addr)); DBG(0, "summary_entry.nid [0x%x]\n", le32_to_cpu(sum_entry.nid)); DBG(0, "--> node block's nid [0x%x]\n", nid); ASSERT_MSG(0, "Invalid node seg summary\n"); } } else if (ret == SEG_TYPE_CUR_NODE) { /* current node segment has no ssa */ } else { ASSERT_MSG(0, "Invalid return value of 'get_sum_entry'"); } return 1; } static int is_valid_ssa_data_blk(struct f2fs_sb_info *sbi, u32 blk_addr, u32 parent_nid, u16 idx_in_node, u8 version) { int ret = 0; struct f2fs_summary sum_entry; ret = get_sum_entry(sbi, blk_addr, &sum_entry); ASSERT(ret == SEG_TYPE_DATA || ret == SEG_TYPE_CUR_DATA); if (le32_to_cpu(sum_entry.nid) != parent_nid || sum_entry.version != version || le16_to_cpu(sum_entry.ofs_in_node) != idx_in_node) { DBG(0, "summary_entry.nid [0x%x]\n", le32_to_cpu(sum_entry.nid)); DBG(0, "summary_entry.version [0x%x]\n", sum_entry.version); DBG(0, "summary_entry.ofs_in_node [0x%x]\n", le16_to_cpu(sum_entry.ofs_in_node)); DBG(0, "parent nid [0x%x]\n", parent_nid); DBG(0, "version from nat [0x%x]\n", version); DBG(0, "idx in parent node [0x%x]\n", idx_in_node); DBG(0, "Target data block addr [0x%x]\n", blk_addr); ASSERT_MSG(0, "Invalid data seg summary\n"); } return 1; } int fsck_chk_node_blk(struct f2fs_sb_info *sbi, struct f2fs_inode *inode, u32 nid, enum FILE_TYPE ftype, enum NODE_TYPE ntype, u32 *blk_cnt) { struct f2fs_fsck *fsck = F2FS_FSCK(sbi); struct node_info ni; struct f2fs_node *node_blk = NULL; int ret = 0; IS_VALID_NID(sbi, nid); if (ftype != F2FS_FT_ORPHAN || f2fs_test_bit(nid, fsck->nat_area_bitmap) != 0x0) f2fs_clear_bit(nid, fsck->nat_area_bitmap); else ASSERT_MSG(0, "nid duplicated [0x%x]\n", nid); ret = get_node_info(sbi, nid, &ni); ASSERT(ret >= 0); /* Is it reserved block? * if block addresss was 0xffff,ffff,ffff,ffff * it means that block was already allocated, but not stored in disk */ if (ni.blk_addr == NEW_ADDR) { fsck->chk.valid_blk_cnt++; fsck->chk.valid_node_cnt++; if (ntype == TYPE_INODE) fsck->chk.valid_inode_cnt++; return 0; } IS_VALID_BLK_ADDR(sbi, ni.blk_addr); is_valid_ssa_node_blk(sbi, nid, ni.blk_addr); if (f2fs_test_bit(BLKOFF_FROM_MAIN(sbi, ni.blk_addr), fsck->sit_area_bitmap) == 0x0) { DBG(0, "SIT bitmap is 0x0. blk_addr[0x%x] %i\n", ni.blk_addr, ni.blk_addr); ASSERT(0); }else{ DBG(0, "SIT bitmap is NOT 0x0. blk_addr[0x%x] %i\n", ni.blk_addr, ni.blk_addr); //ASSERT(0); } if (f2fs_test_bit(BLKOFF_FROM_MAIN(sbi, ni.blk_addr), fsck->main_area_bitmap) == 0x0) { DBG(0, "SIT and main bitmap is 0x0. blk_addr[0x%x] %i\n", ni.blk_addr, ni.blk_addr); fsck->chk.valid_blk_cnt++; fsck->chk.valid_node_cnt++; }else{ DBG(0, "SIT and main bitmap is NOT 0x0. blk_addr[0x%x] %i\n", ni.blk_addr, ni.blk_addr); } node_blk = (struct f2fs_node *)calloc(BLOCK_SZ, 1); ASSERT(node_blk != NULL); ret = dev_read_block(node_blk, ni.blk_addr); ASSERT(ret >= 0); ASSERT_MSG(nid == le32_to_cpu(node_blk->footer.nid), "nid[0x%x] blk_addr[0x%x] footer.nid[0x%x]\n", nid, ni.blk_addr, le32_to_cpu(node_blk->footer.nid)); if (ntype == TYPE_INODE) { ret = fsck_chk_inode_blk(sbi, nid, ftype, node_blk, blk_cnt, &ni); } else { /* it's not inode */ ASSERT(node_blk->footer.nid != node_blk->footer.ino); if (f2fs_test_bit(BLKOFF_FROM_MAIN(sbi, ni.blk_addr), fsck->main_area_bitmap) != 0) { DBG(0, "Duplicated node block. ino[0x%x][0x%x]\n", nid, ni.blk_addr); ASSERT(0); } f2fs_set_bit(BLKOFF_FROM_MAIN(sbi, ni.blk_addr), fsck->main_area_bitmap); switch (ntype) { case TYPE_DIRECT_NODE: ret = fsck_chk_dnode_blk(sbi, inode, nid, ftype, node_blk, blk_cnt, &ni); break; case TYPE_INDIRECT_NODE: ret = fsck_chk_idnode_blk(sbi, inode, nid, ftype, node_blk, blk_cnt); break; case TYPE_DOUBLE_INDIRECT_NODE: ret = fsck_chk_didnode_blk(sbi, inode, nid, ftype, node_blk, blk_cnt); break; default: ASSERT(0); } } ASSERT(ret >= 0); free(node_blk); return 0; } int fsck_chk_inode_blk(struct f2fs_sb_info *sbi, u32 nid, enum FILE_TYPE ftype, struct f2fs_node *node_blk, u32 *blk_cnt, struct node_info *ni) { struct f2fs_fsck *fsck = F2FS_FSCK(sbi); u32 child_cnt = 0, child_files = 0; enum NODE_TYPE ntype; u32 i_links = le32_to_cpu(node_blk->i.i_links); u64 i_blocks = le64_to_cpu(node_blk->i.i_blocks); int idx = 0; int ret = 0; ASSERT(node_blk->footer.nid == node_blk->footer.ino); ASSERT(le32_to_cpu(node_blk->footer.nid) == nid); if (f2fs_test_bit(BLKOFF_FROM_MAIN(sbi, ni->blk_addr), fsck->main_area_bitmap) == 0x0) fsck->chk.valid_inode_cnt++; /* Orphan node. i_links should be 0 */ if (ftype == F2FS_FT_ORPHAN) { ASSERT(i_links == 0); } else { ASSERT(i_links > 0); } if (ftype == F2FS_FT_DIR) { /* not included '.' & '..' */ if (f2fs_test_bit(BLKOFF_FROM_MAIN(sbi, ni->blk_addr), fsck->main_area_bitmap) != 0) { DBG(0, "Duplicated inode blk. ino[0x%x][0x%x]\n", nid, ni->blk_addr); ASSERT(0); } f2fs_set_bit(BLKOFF_FROM_MAIN(sbi, ni->blk_addr), fsck->main_area_bitmap); } else { if (f2fs_test_bit(BLKOFF_FROM_MAIN(sbi, ni->blk_addr), fsck->main_area_bitmap) == 0x0) { f2fs_set_bit(BLKOFF_FROM_MAIN(sbi, ni->blk_addr), fsck->main_area_bitmap); if (i_links > 1) { /* First time. Create new hard link node */ add_into_hard_link_list(sbi, nid, i_links); fsck->chk.multi_hard_link_files++; } } else { if (i_links <= 1) { DBG(0, "Error. Node ID [0x%x]." " There are one more hard links." " But i_links is [0x%x]\n", nid, i_links); ASSERT(0); } DBG(3, "ino[0x%x] has hard links [0x%x]\n", nid, i_links); ret = find_and_dec_hard_link_list(sbi, nid); ASSERT(ret >= 0); /* No need to go deep into the node */ goto out; } } fsck_chk_xattr_blk(sbi, nid, le32_to_cpu(node_blk->i.i_xattr_nid), blk_cnt); if (ftype == F2FS_FT_CHRDEV || ftype == F2FS_FT_BLKDEV || ftype == F2FS_FT_FIFO || ftype == F2FS_FT_SOCK) goto check; if((node_blk->i.i_inline & F2FS_INLINE_DATA)){ DBG(3, "ino[0x%x] has inline data!\n", nid); goto check; } /* check data blocks in inode */ for (idx = 0; idx < ADDRS_PER_INODE(&node_blk->i); idx++) { if (le32_to_cpu(node_blk->i.i_addr[idx]) != 0) { *blk_cnt = *blk_cnt + 1; ret = fsck_chk_data_blk(sbi, &node_blk->i, le32_to_cpu(node_blk->i.i_addr[idx]), &child_cnt, &child_files, (i_blocks == *blk_cnt), ftype, nid, idx, ni->version); ASSERT(ret >= 0); } } /* check node blocks in inode */ for (idx = 0; idx < 5; idx++) { if (idx == 0 || idx == 1) ntype = TYPE_DIRECT_NODE; else if (idx == 2 || idx == 3) ntype = TYPE_INDIRECT_NODE; else if (idx == 4) ntype = TYPE_DOUBLE_INDIRECT_NODE; else ASSERT(0); if (le32_to_cpu(node_blk->i.i_nid[idx]) != 0) { *blk_cnt = *blk_cnt + 1; ret = fsck_chk_node_blk(sbi, &node_blk->i, le32_to_cpu(node_blk->i.i_nid[idx]), ftype, ntype, blk_cnt); ASSERT(ret >= 0); } } check: if (ftype == F2FS_FT_DIR) DBG(1, "Directory Inode: ino: %x name: %s depth: %d child files: %d\n\n", le32_to_cpu(node_blk->footer.ino), node_blk->i.i_name, le32_to_cpu(node_blk->i.i_current_depth), child_files); if (ftype == F2FS_FT_ORPHAN) DBG(1, "Orphan Inode: ino: %x name: %s i_blocks: %lu\n\n", le32_to_cpu(node_blk->footer.ino), node_blk->i.i_name, i_blocks); if ((ftype == F2FS_FT_DIR && i_links != child_cnt) || (i_blocks != *blk_cnt)) { print_node_info(node_blk); DBG(1, "blk cnt [0x%x]\n", *blk_cnt); DBG(1, "child cnt [0x%x]\n", child_cnt); } ASSERT(i_blocks == *blk_cnt); if (ftype == F2FS_FT_DIR) ASSERT(i_links == child_cnt); out: return 0; } int fsck_chk_dnode_blk(struct f2fs_sb_info *sbi, struct f2fs_inode *inode, u32 nid, enum FILE_TYPE ftype, struct f2fs_node *node_blk, u32 *blk_cnt, struct node_info *ni) { int idx; u32 child_cnt = 0, child_files = 0; for (idx = 0; idx < ADDRS_PER_BLOCK; idx++) { if (le32_to_cpu(node_blk->dn.addr[idx]) == 0x0) continue; *blk_cnt = *blk_cnt + 1; fsck_chk_data_blk(sbi, inode, le32_to_cpu(node_blk->dn.addr[idx]), &child_cnt, &child_files, le64_to_cpu(inode->i_blocks) == *blk_cnt, ftype, nid, idx, ni->version); } return 0; } int fsck_chk_idnode_blk(struct f2fs_sb_info *sbi, struct f2fs_inode *inode, u32 nid, enum FILE_TYPE ftype, struct f2fs_node *node_blk, u32 *blk_cnt) { int i = 0; for (i = 0 ; i < NIDS_PER_BLOCK; i++) { if (le32_to_cpu(node_blk->in.nid[i]) == 0x0) continue; *blk_cnt = *blk_cnt + 1; fsck_chk_node_blk(sbi, inode, le32_to_cpu(node_blk->in.nid[i]), ftype, TYPE_DIRECT_NODE, blk_cnt); } return 0; } int fsck_chk_didnode_blk(struct f2fs_sb_info *sbi, struct f2fs_inode *inode, u32 nid, enum FILE_TYPE ftype, struct f2fs_node *node_blk, u32 *blk_cnt) { int i = 0; for (i = 0; i < NIDS_PER_BLOCK; i++) { if (le32_to_cpu(node_blk->in.nid[i]) == 0x0) continue; *blk_cnt = *blk_cnt + 1; fsck_chk_node_blk(sbi, inode, le32_to_cpu(node_blk->in.nid[i]), ftype, TYPE_INDIRECT_NODE, blk_cnt); } return 0; } static void print_dentry(__u32 depth, __u8 *name, struct f2fs_dentry_block *de_blk, int idx, int last_blk) { int last_de = 0; int next_idx = 0; int name_len; int i; int bit_offset; if (config.dbg_lv != -1) return; name_len = le16_to_cpu(de_blk->dentry[idx].name_len); next_idx = idx + (name_len + F2FS_SLOT_LEN - 1) / F2FS_SLOT_LEN; bit_offset = find_next_bit((unsigned long *)de_blk->dentry_bitmap, NR_DENTRY_IN_BLOCK, next_idx); if (bit_offset >= NR_DENTRY_IN_BLOCK && last_blk) last_de = 1; if (tree_mark_size <= depth) { tree_mark_size *= 2; tree_mark = realloc(tree_mark, tree_mark_size); } if (last_de) tree_mark[depth] = '`'; else tree_mark[depth] = '|'; if (tree_mark[depth - 1] == '`') tree_mark[depth - 1] = ' '; for (i = 1; i < depth; i++) printf("%c ", tree_mark[i]); printf("%c-- %s\n", last_de ? '`' : '|', name); } int fsck_chk_dentry_blk(struct f2fs_sb_info *sbi, struct f2fs_inode *inode, u32 blk_addr, u32 *child_cnt, u32 *child_files, int last_blk) { struct f2fs_fsck *fsck = F2FS_FSCK(sbi); int i; int ret = 0; int dentries = 0; u8 *name; u32 hash_code; u32 blk_cnt; u16 name_len;; enum FILE_TYPE ftype; struct f2fs_dentry_block *de_blk; de_blk = (struct f2fs_dentry_block *)calloc(BLOCK_SZ, 1); ASSERT(de_blk != NULL); ret = dev_read_block(de_blk, blk_addr); ASSERT(ret >= 0); fsck->dentry_depth++; for (i = 0; i < NR_DENTRY_IN_BLOCK;) { if (test_bit(i, (unsigned long *)de_blk->dentry_bitmap) == 0x0) { i++; continue; } name_len = le32_to_cpu(de_blk->dentry[i].name_len); name = calloc(name_len + 1, 1); memcpy(name, de_blk->filename[i], name_len); hash_code = f2fs_dentry_hash((const char *)name, name_len); ASSERT(le32_to_cpu(de_blk->dentry[i].hash_code) == hash_code); ftype = de_blk->dentry[i].file_type; /* Becareful. 'dentry.file_type' is not imode. */ if (ftype == F2FS_FT_DIR) { *child_cnt = *child_cnt + 1; if ((name[0] == '.' && name[1] == '.' && name_len == 2) || (name[0] == '.' && name_len == 1)) { i++; free(name); continue; } } DBG(2, "[%3u] - no[0x%x] name[%s] len[0x%x] ino[0x%x] type[0x%x]\n", fsck->dentry_depth, i, name, name_len, le32_to_cpu(de_blk->dentry[i].ino), de_blk->dentry[i].file_type); print_dentry(fsck->dentry_depth, name, de_blk, i, last_blk); blk_cnt = 1; ret = fsck_chk_node_blk(sbi, NULL, le32_to_cpu(de_blk->dentry[i].ino), ftype, TYPE_INODE, &blk_cnt); ASSERT(ret >= 0); i += (name_len + F2FS_SLOT_LEN - 1) / F2FS_SLOT_LEN; dentries++; *child_files = *child_files + 1; free(name); } DBG(1, "[%3d] Dentry Block [0x%x] Done : dentries:%d in %d slots (len:%d)\n\n", fsck->dentry_depth, blk_addr, dentries, NR_DENTRY_IN_BLOCK, F2FS_NAME_LEN); fsck->dentry_depth--; free(de_blk); return 0; } int fsck_chk_data_blk(struct f2fs_sb_info *sbi, struct f2fs_inode *inode, u32 blk_addr, u32 *child_cnt, u32 *child_files, int last_blk, enum FILE_TYPE ftype, u32 parent_nid, u16 idx_in_node, u8 ver) { struct f2fs_fsck *fsck = F2FS_FSCK(sbi); /* Is it reserved block? */ if (blk_addr == NEW_ADDR) { fsck->chk.valid_blk_cnt++; return 0; } IS_VALID_BLK_ADDR(sbi, blk_addr); is_valid_ssa_data_blk(sbi, blk_addr, parent_nid, idx_in_node, ver); if (f2fs_test_bit(BLKOFF_FROM_MAIN(sbi, blk_addr), fsck->sit_area_bitmap) == 0x0) { ASSERT_MSG(0, "SIT bitmap is 0x0. blk_addr[0x%x]\n", blk_addr); } if (f2fs_test_bit(BLKOFF_FROM_MAIN(sbi, blk_addr), fsck->main_area_bitmap) != 0) { ASSERT_MSG(0, "Duplicated data block. pnid[0x%x] idx[0x%x] blk_addr[0x%x]\n", parent_nid, idx_in_node, blk_addr); } f2fs_set_bit(BLKOFF_FROM_MAIN(sbi, blk_addr), fsck->main_area_bitmap); fsck->chk.valid_blk_cnt++; if (ftype == F2FS_FT_DIR) { fsck_chk_dentry_blk(sbi, inode, blk_addr, child_cnt, child_files, last_blk); } return 0; } int fsck_chk_orphan_node(struct f2fs_sb_info *sbi) { int ret = 0; u32 blk_cnt = 0; block_t start_blk, orphan_blkaddr, i, j; struct f2fs_orphan_block *orphan_blk; if (!is_set_ckpt_flags(F2FS_CKPT(sbi), CP_ORPHAN_PRESENT_FLAG)) return 0; start_blk = __start_cp_addr(sbi) + 1; orphan_blkaddr = __start_sum_addr(sbi) - 1; orphan_blk = calloc(BLOCK_SZ, 1); for (i = 0; i < orphan_blkaddr; i++) { dev_read_block(orphan_blk, start_blk + i); for (j = 0; j < le32_to_cpu(orphan_blk->entry_count); j++) { nid_t ino = le32_to_cpu(orphan_blk->ino[j]); DBG(1, "[%3d] ino [0x%x]\n", i, ino); blk_cnt = 1; ret = fsck_chk_node_blk(sbi, NULL, ino, F2FS_FT_ORPHAN, TYPE_INODE, &blk_cnt); ASSERT(ret >= 0); } memset(orphan_blk, 0, BLOCK_SZ); } free(orphan_blk); return 0; } int fsck_chk_xattr_blk(struct f2fs_sb_info *sbi, u32 ino, u32 x_nid, u32 *blk_cnt) { struct f2fs_fsck *fsck = F2FS_FSCK(sbi); struct node_info ni; if (x_nid == 0x0) return 0; if (f2fs_test_bit(x_nid, fsck->nat_area_bitmap) != 0x0) { f2fs_clear_bit(x_nid, fsck->nat_area_bitmap); } else { ASSERT_MSG(0, "xattr_nid duplicated [0x%x]\n", x_nid); } *blk_cnt = *blk_cnt + 1; fsck->chk.valid_blk_cnt++; fsck->chk.valid_node_cnt++; ASSERT(get_node_info(sbi, x_nid, &ni) >= 0); if (f2fs_test_bit(BLKOFF_FROM_MAIN(sbi, ni.blk_addr), fsck->main_area_bitmap) != 0) { ASSERT_MSG(0, "Duplicated node block for x_attr. " "x_nid[0x%x] block addr[0x%x]\n", x_nid, ni.blk_addr); } f2fs_set_bit(BLKOFF_FROM_MAIN(sbi, ni.blk_addr), fsck->main_area_bitmap); DBG(2, "ino[0x%x] x_nid[0x%x]\n", ino, x_nid); return 0; } int fsck_init(struct f2fs_sb_info *sbi) { struct f2fs_fsck *fsck = F2FS_FSCK(sbi); struct f2fs_sm_info *sm_i = SM_I(sbi); /* * We build three bitmap for main/sit/nat so that may check consistency of filesystem. * 1. main_area_bitmap will be used to check whether all blocks of main area is used or not. * 2. nat_area_bitmap has bitmap information of used nid in NAT. * 3. sit_area_bitmap has bitmap information of used main block. * At Last sequence, we compare main_area_bitmap with sit_area_bitmap. */ fsck->nr_main_blks = sm_i->main_segments << sbi->log_blocks_per_seg; fsck->main_area_bitmap_sz = (fsck->nr_main_blks + 7) / 8; fsck->main_area_bitmap = calloc(fsck->main_area_bitmap_sz, 1); ASSERT(fsck->main_area_bitmap != NULL); build_nat_area_bitmap(sbi); build_sit_area_bitmap(sbi); tree_mark = calloc(tree_mark_size, 1); return 0; } int fsck_verify(struct f2fs_sb_info *sbi) { int i = 0; int ret = 0; u32 nr_unref_nid = 0; struct f2fs_fsck *fsck = F2FS_FSCK(sbi); struct hard_link_node *node = NULL; printf("\n"); for (i = 0; i < fsck->nr_nat_entries; i++) { if (f2fs_test_bit(i, fsck->nat_area_bitmap) != 0) { printf("NID[0x%x] is unreachable\n", i); nr_unref_nid++; } } if (fsck->hard_link_list_head != NULL) { node = fsck->hard_link_list_head; while (node) { printf("NID[0x%x] has [0x%x] more unreachable links\n", node->nid, node->links); node = node->next; } } printf("[FSCK] Unreachable nat entries "); if (nr_unref_nid == 0x0) { printf(" [Ok..] [0x%x]\n", nr_unref_nid); } else { printf(" [Fail] [0x%x]\n", nr_unref_nid); ret = EXIT_ERR_CODE; } printf("[FSCK] SIT valid block bitmap checking "); if (memcmp(fsck->sit_area_bitmap, fsck->main_area_bitmap, fsck->sit_area_bitmap_sz) == 0x0) { printf("[Ok..]\n"); } else { printf("[Fail]\n"); ret = EXIT_ERR_CODE; } printf("[FSCK] Hard link checking for regular file "); if (fsck->hard_link_list_head == NULL) { printf(" [Ok..] [0x%x]\n", fsck->chk.multi_hard_link_files); } else { printf(" [Fail] [0x%x]\n", fsck->chk.multi_hard_link_files); ret = EXIT_ERR_CODE; } printf("[FSCK] valid_block_count matching with CP "); if (sbi->total_valid_block_count == fsck->chk.valid_blk_cnt) { printf(" [Ok..] [0x%lx]\n", fsck->chk.valid_blk_cnt); } else { printf(" [Fail] [0x%lx]\n", fsck->chk.valid_blk_cnt); ret = EXIT_ERR_CODE; } printf("[FSCK] valid_node_count matcing with CP (de lookup) "); if (sbi->total_valid_node_count == fsck->chk.valid_node_cnt) { printf(" [Ok..] [0x%x]\n", fsck->chk.valid_node_cnt); } else { printf(" [Fail] [0x%x]\n", fsck->chk.valid_node_cnt); ret = EXIT_ERR_CODE; } printf("[FSCK] valid_node_count matcing with CP (nat lookup) "); if (sbi->total_valid_node_count == fsck->chk.valid_nat_entry_cnt) { printf(" [Ok..] [0x%x]\n", fsck->chk.valid_nat_entry_cnt); } else { printf(" [Fail] [0x%x]\n", fsck->chk.valid_nat_entry_cnt); ret = EXIT_ERR_CODE; } printf("[FSCK] valid_inode_count matched with CP "); if (sbi->total_valid_inode_count == fsck->chk.valid_inode_cnt) { printf(" [Ok..] [0x%x]\n", fsck->chk.valid_inode_cnt); } else { printf(" [Fail] [0x%x]\n", fsck->chk.valid_inode_cnt); ret = EXIT_ERR_CODE; } return ret; } void fsck_free(struct f2fs_sb_info *sbi) { struct f2fs_fsck *fsck = F2FS_FSCK(sbi); if (fsck->main_area_bitmap) free(fsck->main_area_bitmap); if (fsck->nat_area_bitmap) free(fsck->nat_area_bitmap); if (fsck->sit_area_bitmap) free(fsck->sit_area_bitmap); if (tree_mark) free(tree_mark); } partclone-0.2.86/src/f2fs/fsck.h000066400000000000000000000077211262102574200163340ustar00rootroot00000000000000/** * fsck.h * * Copyright (c) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.com/ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ #ifndef _FSCK_H_ #define _FSCK_H_ #include "f2fs.h" /* fsck.c */ struct orphan_info { u32 nr_inodes; u32 *ino_list; }; struct f2fs_fsck { struct f2fs_sb_info sbi; struct orphan_info orphani; struct chk_result { u64 valid_blk_cnt; u32 valid_nat_entry_cnt; u32 valid_node_cnt; u32 valid_inode_cnt; u32 multi_hard_link_files; u64 sit_valid_blocks; u32 sit_free_segs; } chk; struct hard_link_node *hard_link_list_head; char *main_seg_usage; char *main_area_bitmap; char *nat_area_bitmap; char *sit_area_bitmap; u64 main_area_bitmap_sz; u32 nat_area_bitmap_sz; u32 sit_area_bitmap_sz; u64 nr_main_blks; u32 nr_nat_entries; u32 dentry_depth; }; #define BLOCK_SZ 4096 struct block { unsigned char buf[BLOCK_SZ]; }; enum NODE_TYPE { TYPE_INODE = 37, TYPE_DIRECT_NODE = 43, TYPE_INDIRECT_NODE = 53, TYPE_DOUBLE_INDIRECT_NODE = 67 }; struct hard_link_node { u32 nid; u32 links; struct hard_link_node *next; }; enum seg_type { SEG_TYPE_DATA, SEG_TYPE_CUR_DATA, SEG_TYPE_NODE, SEG_TYPE_CUR_NODE, SEG_TYPE_MAX, }; extern int fsck_chk_xattr_blk(struct f2fs_sb_info *sbi, u32 ino, u32 x_nid, u32 *blk_cnt); extern int fsck_chk_orphan_node(struct f2fs_sb_info *sbi); extern int fsck_chk_node_blk(struct f2fs_sb_info *sbi, struct f2fs_inode *inode, u32 nid, enum FILE_TYPE ftype, enum NODE_TYPE ntype, u32 *blk_cnt); extern int fsck_chk_inode_blk(struct f2fs_sb_info *sbi, u32 nid, enum FILE_TYPE ftype, struct f2fs_node *node_blk, u32 *blk_cnt, struct node_info *ni); extern int fsck_chk_dnode_blk(struct f2fs_sb_info *sbi, struct f2fs_inode *inode, u32 nid, enum FILE_TYPE ftype, struct f2fs_node *node_blk, u32 *blk_cnt, struct node_info *ni); extern int fsck_chk_idnode_blk(struct f2fs_sb_info *sbi, struct f2fs_inode *inode, u32 nid, enum FILE_TYPE ftype, struct f2fs_node *node_blk, u32 *blk_cnt); extern int fsck_chk_didnode_blk(struct f2fs_sb_info *sbi, struct f2fs_inode *inode, u32 nid, enum FILE_TYPE ftype, struct f2fs_node *node_blk, u32 *blk_cnt); extern int fsck_chk_data_blk(struct f2fs_sb_info *sbi, struct f2fs_inode *inode, u32 blk_addr, u32 *child_cnt, u32 *child_files, int last_blk, enum FILE_TYPE ftype, u32 parent_nid, u16 idx_in_node, u8 ver); extern int fsck_chk_dentry_blk(struct f2fs_sb_info *sbi, struct f2fs_inode *inode, u32 blk_addr, u32 *child_cnt, u32 *child_files, int last_blk); extern void print_node_info(struct f2fs_node *node_block); extern void print_inode_info(struct f2fs_inode *inode); extern struct seg_entry *get_seg_entry(struct f2fs_sb_info *sbi, unsigned int segno); extern int get_sum_block(struct f2fs_sb_info *sbi, unsigned int segno, struct f2fs_summary_block *sum_blk); extern int get_sum_entry(struct f2fs_sb_info *sbi, u32 blk_addr, struct f2fs_summary *sum_entry); extern int get_node_info(struct f2fs_sb_info *sbi, nid_t nid, struct node_info *ni); extern void build_nat_area_bitmap(struct f2fs_sb_info *sbi); extern int build_sit_area_bitmap(struct f2fs_sb_info *sbi); extern int fsck_init(struct f2fs_sb_info *sbi); extern int fsck_verify(struct f2fs_sb_info *sbi); extern void fsck_free(struct f2fs_sb_info *sbi); extern int f2fs_do_mount(struct f2fs_sb_info *sbi); extern void f2fs_do_umount(struct f2fs_sb_info *sbi); /* dump.c */ struct dump_option { nid_t nid; int start_sit; int end_sit; int start_ssa; int end_ssa; u32 blk_addr; }; extern void sit_dump(struct f2fs_sb_info *sbi, int start_sit, int end_sit); extern void ssa_dump(struct f2fs_sb_info *sbi, int start_ssa, int end_ssa); extern int dump_node(struct f2fs_sb_info *sbi, nid_t nid); extern int dump_inode_from_blkaddr(struct f2fs_sb_info *sbi, u32 blk_addr); #endif /* _FSCK_H_ */ partclone-0.2.86/src/f2fs/libf2fs.c000066400000000000000000000256511262102574200167320ustar00rootroot00000000000000/** * libf2fs.c * * Copyright (c) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.com/ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ #define _LARGEFILE64_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include "f2fs_fs.h" struct f2fs_configuration config; void ASCIIToUNICODE(u_int16_t *out_buf, u_int8_t *in_buf) { u_int8_t *pchTempPtr = in_buf; u_int16_t *pwTempPtr = out_buf; while (*pchTempPtr != '\0') { *pwTempPtr = (u_int16_t)*pchTempPtr; pchTempPtr++; pwTempPtr++; } *pwTempPtr = '\0'; return; } int log_base_2(u_int32_t num) { int ret = 0; if (num <= 0 || (num & (num - 1)) != 0) return -1; while (num >>= 1) ret++; return ret; } /* * f2fs bit operations */ static const int bits_in_byte[256] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, }; int get_bits_in_byte(unsigned char n) { return bits_in_byte[n]; } int set_bit(unsigned int nr,void * addr) { int mask, retval; unsigned char *ADDR = (unsigned char *) addr; ADDR += nr >> 3; mask = 1 << ((nr & 0x07)); retval = mask & *ADDR; *ADDR |= mask; return retval; } int clear_bit(unsigned int nr, void * addr) { int mask, retval; unsigned char *ADDR = (unsigned char *) addr; ADDR += nr >> 3; mask = 1 << ((nr & 0x07)); retval = mask & *ADDR; *ADDR &= ~mask; return retval; } int test_bit(unsigned int nr, const void * addr) { const __u32 *p = (const __u32 *)addr; nr = nr ^ 0; return ((1 << (nr & 31)) & (p[nr >> 5])) != 0; } int f2fs_test_bit(unsigned int nr, const char *p) { int mask; char *addr = (char *)p; addr += (nr >> 3); mask = 1 << (7 - (nr & 0x07)); return (mask & *addr) != 0; } int f2fs_set_bit(unsigned int nr, char *addr) { int mask; int ret; addr += (nr >> 3); mask = 1 << (7 - (nr & 0x07)); ret = mask & *addr; *addr |= mask; return ret; } int f2fs_clear_bit(unsigned int nr, char *addr) { int mask; int ret; addr += (nr >> 3); mask = 1 << (7 - (nr & 0x07)); ret = mask & *addr; *addr &= ~mask; return ret; } static inline unsigned long __ffs(unsigned long word) { int num = 0; #if BITS_PER_LONG == 64 if ((word & 0xffffffff) == 0) { num += 32; word >>= 32; } #endif if ((word & 0xffff) == 0) { num += 16; word >>= 16; } if ((word & 0xff) == 0) { num += 8; word >>= 8; } if ((word & 0xf) == 0) { num += 4; word >>= 4; } if ((word & 0x3) == 0) { num += 2; word >>= 2; } if ((word & 0x1) == 0) num += 1; return num; } unsigned long find_next_bit(const unsigned long *addr, unsigned long size, unsigned long offset) { const unsigned long *p = addr + BIT_WORD(offset); unsigned long result = offset & ~(BITS_PER_LONG-1); unsigned long tmp; if (offset >= size) return size; size -= result; offset %= BITS_PER_LONG; if (offset) { tmp = *(p++); tmp &= (~0UL << offset); if (size < BITS_PER_LONG) goto found_first; if (tmp) goto found_middle; size -= BITS_PER_LONG; result += BITS_PER_LONG; } while (size & ~(BITS_PER_LONG-1)) { if ((tmp = *(p++))) goto found_middle; result += BITS_PER_LONG; size -= BITS_PER_LONG; } if (!size) return result; tmp = *p; found_first: tmp &= (~0UL >> (BITS_PER_LONG - size)); if (tmp == 0UL) /* Are any bits set? */ return result + size; /* Nope. */ found_middle: return result + __ffs(tmp); } /* * Hashing code adapted from ext3 */ #define DELTA 0x9E3779B9 static void TEA_transform(unsigned int buf[4], unsigned int const in[]) { __u32 sum = 0; __u32 b0 = buf[0], b1 = buf[1]; __u32 a = in[0], b = in[1], c = in[2], d = in[3]; int n = 16; do { sum += DELTA; b0 += ((b1 << 4)+a) ^ (b1+sum) ^ ((b1 >> 5)+b); b1 += ((b0 << 4)+c) ^ (b0+sum) ^ ((b0 >> 5)+d); } while (--n); buf[0] += b0; buf[1] += b1; } static void str2hashbuf(const char *msg, int len, unsigned int *buf, int num) { unsigned pad, val; int i; pad = (__u32)len | ((__u32)len << 8); pad |= pad << 16; val = pad; if (len > num * 4) len = num * 4; for (i = 0; i < len; i++) { if ((i % 4) == 0) val = pad; val = msg[i] + (val << 8); if ((i % 4) == 3) { *buf++ = val; val = pad; num--; } } if (--num >= 0) *buf++ = val; while (--num >= 0) *buf++ = pad; } /** * Return hash value of directory entry * @param name dentry name * @param len name lenth * @return return on success hash value, errno on failure */ f2fs_hash_t f2fs_dentry_hash(const char *name, int len) { __u32 hash; f2fs_hash_t f2fs_hash; const char *p; __u32 in[8], buf[4]; /* special hash codes for special dentries */ if (name[0] == '.') { if (name[1] == '\0') { f2fs_hash = F2FS_DOT_HASH; goto exit; } if (name[1] == '.' && name[2] == '\0') { f2fs_hash = F2FS_DDOT_HASH; goto exit; } } /* Initialize the default seed for the hash checksum functions */ buf[0] = 0x67452301; buf[1] = 0xefcdab89; buf[2] = 0x98badcfe; buf[3] = 0x10325476; p = name; while (len > 0) { str2hashbuf(p, len, in, 4); TEA_transform(buf, in); len -= 16; p += 16; } hash = buf[0]; f2fs_hash = hash; exit: f2fs_hash &= ~F2FS_HASH_COL_BIT; return f2fs_hash; } unsigned int addrs_per_inode(struct f2fs_inode *i) { if (i->i_inline & F2FS_INLINE_XATTR) return DEF_ADDRS_PER_INODE - F2FS_INLINE_XATTR_ADDRS; return DEF_ADDRS_PER_INODE; } /* * CRC32 */ #define CRCPOLY_LE 0xedb88320 u_int32_t f2fs_cal_crc32(u_int32_t crc, void *buf, int len) { int i; unsigned char *p = (unsigned char *)buf; while (len--) { crc ^= *p++; for (i = 0; i < 8; i++) crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0); } return crc; } int f2fs_crc_valid(u_int32_t blk_crc, void *buf, int len) { u_int32_t cal_crc = 0; cal_crc = f2fs_cal_crc32(F2FS_SUPER_MAGIC, buf, len); if (cal_crc != blk_crc) { DBG(0,"CRC validation failed: cal_crc = %u \ blk_crc = %u buff_size = 0x%x", cal_crc, blk_crc, len); return -1; } return 0; } /* * device information */ void f2fs_init_configuration(struct f2fs_configuration *c) { c->sector_size = DEFAULT_SECTOR_SIZE; c->sectors_per_blk = DEFAULT_SECTORS_PER_BLOCK; c->blks_per_seg = DEFAULT_BLOCKS_PER_SEGMENT; /* calculated by overprovision ratio */ c->reserved_segments = 48; c->overprovision = 5; c->segs_per_sec = 1; c->secs_per_zone = 1; c->heap = 1; c->vol_label = ""; c->device_name = NULL; c->trim = 1; } static int is_mounted(const char *mpt, const char *device) { FILE *file = NULL; struct mntent *mnt = NULL; file = setmntent(mpt, "r"); if (file == NULL) return 0; while ((mnt = getmntent(file)) != NULL) { if (!strcmp(device, mnt->mnt_fsname)) break; } endmntent(file); return mnt ? 1 : 0; } int f2fs_dev_is_umounted(struct f2fs_configuration *c) { struct stat st_buf; int ret = 0; ret = is_mounted(MOUNTED, c->device_name); if (ret) { MSG(0, "\tError: Not available on mounted device!\n"); return -1; } /* * if failed due to /etc/mtab file not present * try with /proc/mounts. */ ret = is_mounted("/proc/mounts", c->device_name); if (ret) { MSG(0, "\tError: Not available on mounted device!\n"); return -1; } /* * If f2fs is umounted with -l, the process can still use * the file system. In this case, we should not format. */ if (stat(c->device_name, &st_buf) == 0 && S_ISBLK(st_buf.st_mode)) { int fd = open(c->device_name, O_RDONLY | O_EXCL); if (fd >= 0) { close(fd); } else if (errno == EBUSY) { MSG(0, "\tError: In use by the system!\n"); return -1; } } return 0; } int f2fs_get_device_info(struct f2fs_configuration *c) { int32_t fd = 0; int32_t sector_size; struct stat stat_buf; struct hd_geometry geom; fd = open(c->device_name, O_RDWR); if (fd < 0) { MSG(0, "\tError: Failed to open the device!\n"); return -1; } c->fd = fd; if (fstat(fd, &stat_buf) < 0 ) { MSG(0, "\tError: Failed to get the device stat!\n"); return -1; } if (S_ISREG(stat_buf.st_mode)) { c->total_sectors = stat_buf.st_size / c->sector_size; } else if (S_ISBLK(stat_buf.st_mode)) { if (ioctl(fd, BLKSSZGET, §or_size) < 0) { MSG(0, "\tError: Using the default sector size\n"); } else { if (c->sector_size < sector_size) { MSG(0, "\tError: Cannot set the sector size to:" " %d as the device does not support" "\nSetting the sector size to : %d\n", c->sector_size, sector_size); c->sector_size = sector_size; c->sectors_per_blk = PAGE_SIZE / sector_size; } } if (ioctl(fd, BLKGETSIZE, &c->total_sectors) < 0) { MSG(0, "\tError: Cannot get the device size\n"); return -1; } if (ioctl(fd, HDIO_GETGEO, &geom) < 0) c->start_sector = 0; else c->start_sector = geom.start; } else { MSG(0, "\tError: Volume type is not supported!!!\n"); return -1; } //MSG(0, "Info: sector size = %u\n", c->sector_size); //MSG(0, "Info: total sectors = %"PRIu64" (in 512bytes)\n", // c->total_sectors); if (c->total_sectors < (F2FS_MIN_VOLUME_SIZE / DEFAULT_SECTOR_SIZE)) { MSG(0, "Error: Min volume size supported is %d\n", F2FS_MIN_VOLUME_SIZE); return -1; } return 0; } /* * IO interfaces */ int dev_read(void *buf, __u64 offset, size_t len) { if (lseek64(config.fd, (off64_t)offset, SEEK_SET) < 0) return -1; if (read(config.fd, buf, len) < 0) return -1; return 0; } int dev_write(void *buf, __u64 offset, size_t len) { if (lseek64(config.fd, (off64_t)offset, SEEK_SET) < 0) return -1; if (write(config.fd, buf, len) < 0) return -1; return 0; } int dev_read_block(void *buf, __u64 blk_addr) { return dev_read(buf, blk_addr * F2FS_BLKSIZE, F2FS_BLKSIZE); } int dev_read_blocks(void *buf, __u64 addr, __u32 nr_blks) { return dev_read(buf, addr * F2FS_BLKSIZE, nr_blks * F2FS_BLKSIZE); } partclone-0.2.86/src/f2fs/list.h000066400000000000000000000046271262102574200163630ustar00rootroot00000000000000 #define POISON_POINTER_DELTA 0 #define LIST_POISON1 ((void *) 0x00100100 + POISON_POINTER_DELTA) #define LIST_POISON2 ((void *) 0x00200200 + POISON_POINTER_DELTA) #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) #define container_of(ptr, type, member) ({ \ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ (type *)( (char *)__mptr - offsetof(type,member) );}) struct list_head { struct list_head *next, *prev; }; #define LIST_HEAD_INIT(name) { &(name), &(name) } #define LIST_HEAD(name) \ struct list_head name = LIST_HEAD_INIT(name) static inline void INIT_LIST_HEAD(struct list_head *list) { list->next = list; list->prev = list; } static inline void __list_add(struct list_head *new, struct list_head *prev, struct list_head *next) { next->prev = new; new->next = next; new->prev = prev; prev->next = new; } static inline void list_add(struct list_head *new, struct list_head *head) { __list_add(new, head, head->next); } static inline void list_add_tail(struct list_head *new, struct list_head *head) { __list_add(new, head->prev, head); } static inline void __list_del(struct list_head * prev, struct list_head * next) { next->prev = prev; prev->next = next; } static inline void __list_del_entry(struct list_head *entry) { __list_del(entry->prev, entry->next); } static inline void list_del(struct list_head *entry) { __list_del(entry->prev, entry->next); entry->next = LIST_POISON1; entry->prev = LIST_POISON2; } static inline int list_empty(const struct list_head *head) { return head->next == head; } #define list_entry(ptr, type, member) \ container_of(ptr, type, member) #define list_for_each(pos, head) \ for (pos = (head)->next; pos != (head); pos = pos->next) #define list_for_each_safe(pos, n, head) \ for (pos = (head)->next, n = pos->next; pos != (head); \ pos = n, n = pos->next) #define list_for_each_entry(pos, head, member) \ for (pos = list_entry((head)->next, typeof(*pos), member); \ &pos->member != (head); \ pos = list_entry(pos->member.next, typeof(*pos), member)) #define list_for_each_entry_safe(pos, n, head, member) \ for (pos = list_entry((head)->next, typeof(*pos), member), \ n = list_entry(pos->member.next, typeof(*pos), member); \ &pos->member != (head); \ pos = n, n = list_entry(n->member.next, typeof(*n), member)) partclone-0.2.86/src/f2fs/mount.c000066400000000000000000000722311262102574200165410ustar00rootroot00000000000000/** * mount.c * * Copyright (c) 2013 Samsung Electronics Co., Ltd. * http://www.samsung.com/ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ #include "fsck.h" void print_inode_info(struct f2fs_inode *inode) { int i = 0; int namelen = le32_to_cpu(inode->i_namelen); DISP_u32(inode, i_mode); DISP_u32(inode, i_uid); DISP_u32(inode, i_gid); DISP_u32(inode, i_links); DISP_u64(inode, i_size); DISP_u64(inode, i_blocks); DISP_u64(inode, i_atime); DISP_u32(inode, i_atime_nsec); DISP_u64(inode, i_ctime); DISP_u32(inode, i_ctime_nsec); DISP_u64(inode, i_mtime); DISP_u32(inode, i_mtime_nsec); DISP_u32(inode, i_generation); DISP_u32(inode, i_current_depth); DISP_u32(inode, i_xattr_nid); DISP_u32(inode, i_flags); DISP_u32(inode, i_pino); if (namelen) { DISP_u32(inode, i_namelen); inode->i_name[namelen] = '\0'; DISP_utf(inode, i_name); } printf("i_ext: fofs:%x blkaddr:%x len:%x\n", inode->i_ext.fofs, inode->i_ext.blk_addr, inode->i_ext.len); DISP_u32(inode, i_addr[0]); /* Pointers to data blocks */ DISP_u32(inode, i_addr[1]); /* Pointers to data blocks */ DISP_u32(inode, i_addr[2]); /* Pointers to data blocks */ DISP_u32(inode, i_addr[3]); /* Pointers to data blocks */ for (i = 4; i < ADDRS_PER_INODE(inode); i++) { if (inode->i_addr[i] != 0x0) { printf("i_addr[0x%x] points data block\r\t\t\t\t[0x%4x]\n", i, inode->i_addr[i]); break; } } DISP_u32(inode, i_nid[0]); /* direct */ DISP_u32(inode, i_nid[1]); /* direct */ DISP_u32(inode, i_nid[2]); /* indirect */ DISP_u32(inode, i_nid[3]); /* indirect */ DISP_u32(inode, i_nid[4]); /* double indirect */ printf("\n"); } void print_node_info(struct f2fs_node *node_block) { nid_t ino = le32_to_cpu(node_block->footer.ino); nid_t nid = le32_to_cpu(node_block->footer.nid); /* Is this inode? */ if (ino == nid) { DBG(0, "Node ID [0x%x:%u] is inode\n", nid, nid); print_inode_info(&node_block->i); } else { int i; u32 *dump_blk = (u32 *)node_block; DBG(0, "Node ID [0x%x:%u] is direct node or indirect node.\n", nid, nid); for (i = 0; i <= 10; i++) MSG(0, "[%d]\t\t\t[0x%8x : %d]\n", i, dump_blk[i], dump_blk[i]); } } void print_raw_sb_info(struct f2fs_sb_info *sbi) { struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); if (!config.dbg_lv) return; printf("\n"); printf("+--------------------------------------------------------+\n"); printf("| Super block |\n"); printf("+--------------------------------------------------------+\n"); DISP_u32(sb, magic); DISP_u32(sb, major_ver); DISP_u32(sb, minor_ver); DISP_u32(sb, log_sectorsize); DISP_u32(sb, log_sectors_per_block); DISP_u32(sb, log_blocksize); DISP_u32(sb, log_blocks_per_seg); DISP_u32(sb, segs_per_sec); DISP_u32(sb, secs_per_zone); DISP_u32(sb, checksum_offset); DISP_u64(sb, block_count); DISP_u32(sb, section_count); DISP_u32(sb, segment_count); DISP_u32(sb, segment_count_ckpt); DISP_u32(sb, segment_count_sit); DISP_u32(sb, segment_count_nat); DISP_u32(sb, segment_count_ssa); DISP_u32(sb, segment_count_main); DISP_u32(sb, segment0_blkaddr); DISP_u32(sb, cp_blkaddr); DISP_u32(sb, sit_blkaddr); DISP_u32(sb, nat_blkaddr); DISP_u32(sb, ssa_blkaddr); DISP_u32(sb, main_blkaddr); DISP_u32(sb, root_ino); DISP_u32(sb, node_ino); DISP_u32(sb, meta_ino); printf("\n"); } void print_ckpt_info(struct f2fs_sb_info *sbi) { struct f2fs_checkpoint *cp = F2FS_CKPT(sbi); if (!config.dbg_lv) return; printf("\n"); printf("+--------------------------------------------------------+\n"); printf("| Checkpoint |\n"); printf("+--------------------------------------------------------+\n"); DISP_u64(cp, checkpoint_ver); DISP_u64(cp, user_block_count); DISP_u64(cp, valid_block_count); DISP_u32(cp, rsvd_segment_count); DISP_u32(cp, overprov_segment_count); DISP_u32(cp, free_segment_count); DISP_u32(cp, alloc_type[CURSEG_HOT_NODE]); DISP_u32(cp, alloc_type[CURSEG_WARM_NODE]); DISP_u32(cp, alloc_type[CURSEG_COLD_NODE]); DISP_u32(cp, cur_node_segno[0]); DISP_u32(cp, cur_node_segno[1]); DISP_u32(cp, cur_node_segno[2]); DISP_u32(cp, cur_node_blkoff[0]); DISP_u32(cp, cur_node_blkoff[1]); DISP_u32(cp, cur_node_blkoff[2]); DISP_u32(cp, alloc_type[CURSEG_HOT_DATA]); DISP_u32(cp, alloc_type[CURSEG_WARM_DATA]); DISP_u32(cp, alloc_type[CURSEG_COLD_DATA]); DISP_u32(cp, cur_data_segno[0]); DISP_u32(cp, cur_data_segno[1]); DISP_u32(cp, cur_data_segno[2]); DISP_u32(cp, cur_data_blkoff[0]); DISP_u32(cp, cur_data_blkoff[1]); DISP_u32(cp, cur_data_blkoff[2]); DISP_u32(cp, ckpt_flags); DISP_u32(cp, cp_pack_total_block_count); DISP_u32(cp, cp_pack_start_sum); DISP_u32(cp, valid_node_count); DISP_u32(cp, valid_inode_count); DISP_u32(cp, next_free_nid); DISP_u32(cp, sit_ver_bitmap_bytesize); DISP_u32(cp, nat_ver_bitmap_bytesize); DISP_u32(cp, checksum_offset); DISP_u64(cp, elapsed_time); DISP_u32(cp, sit_nat_version_bitmap[0]); printf("\n\n"); } int sanity_check_raw_super(struct f2fs_super_block *raw_super) { unsigned int blocksize; if (F2FS_SUPER_MAGIC != le32_to_cpu(raw_super->magic)) { return -1; } if (F2FS_BLKSIZE != PAGE_CACHE_SIZE) { return -1; } blocksize = 1 << le32_to_cpu(raw_super->log_blocksize); if (F2FS_BLKSIZE != blocksize) { return -1; } if (F2FS_LOG_SECTOR_SIZE != le32_to_cpu(raw_super->log_sectorsize)) { return -1; } if (F2FS_LOG_SECTORS_PER_BLOCK != le32_to_cpu(raw_super->log_sectors_per_block)) { return -1; } return 0; } int validate_super_block(struct f2fs_sb_info *sbi, int block) { u64 offset = (block + 1) * F2FS_SUPER_OFFSET; sbi->raw_super = malloc(sizeof(struct f2fs_super_block)); if (dev_read(sbi->raw_super, offset, sizeof(struct f2fs_super_block))) return -1; if (!sanity_check_raw_super(sbi->raw_super)) return 0; free(sbi->raw_super); MSG(0, "\tCan't find a valid F2FS filesystem in %d superblock\n", block); return -EINVAL; } int init_sb_info(struct f2fs_sb_info *sbi) { struct f2fs_super_block *raw_super = sbi->raw_super; sbi->log_sectors_per_block = le32_to_cpu(raw_super->log_sectors_per_block); sbi->log_blocksize = le32_to_cpu(raw_super->log_blocksize); sbi->blocksize = 1 << sbi->log_blocksize; sbi->log_blocks_per_seg = le32_to_cpu(raw_super->log_blocks_per_seg); sbi->blocks_per_seg = 1 << sbi->log_blocks_per_seg; sbi->segs_per_sec = le32_to_cpu(raw_super->segs_per_sec); sbi->secs_per_zone = le32_to_cpu(raw_super->secs_per_zone); sbi->total_sections = le32_to_cpu(raw_super->section_count); sbi->total_node_count = (le32_to_cpu(raw_super->segment_count_nat) / 2) * sbi->blocks_per_seg * NAT_ENTRY_PER_BLOCK; sbi->root_ino_num = le32_to_cpu(raw_super->root_ino); sbi->node_ino_num = le32_to_cpu(raw_super->node_ino); sbi->meta_ino_num = le32_to_cpu(raw_super->meta_ino); sbi->cur_victim_sec = NULL_SEGNO; return 0; } void *validate_checkpoint(struct f2fs_sb_info *sbi, block_t cp_addr, unsigned long long *version) { void *cp_page_1, *cp_page_2; struct f2fs_checkpoint *cp_block; unsigned long blk_size = sbi->blocksize; unsigned long long cur_version = 0, pre_version = 0; unsigned int crc = 0; size_t crc_offset; /* Read the 1st cp block in this CP pack */ cp_page_1 = malloc(PAGE_SIZE); if (dev_read_block(cp_page_1, cp_addr) < 0) return NULL; cp_block = (struct f2fs_checkpoint *)cp_page_1; crc_offset = le32_to_cpu(cp_block->checksum_offset); if (crc_offset >= blk_size) goto invalid_cp1; crc = *(unsigned int *)((unsigned char *)cp_block + crc_offset); if (f2fs_crc_valid(crc, cp_block, crc_offset)) goto invalid_cp1; pre_version = le64_to_cpu(cp_block->checkpoint_ver); /* Read the 2nd cp block in this CP pack */ cp_page_2 = malloc(PAGE_SIZE); cp_addr += le32_to_cpu(cp_block->cp_pack_total_block_count) - 1; if (dev_read_block(cp_page_2, cp_addr) < 0) goto invalid_cp2; cp_block = (struct f2fs_checkpoint *)cp_page_2; crc_offset = le32_to_cpu(cp_block->checksum_offset); if (crc_offset >= blk_size) goto invalid_cp2; crc = *(unsigned int *)((unsigned char *)cp_block + crc_offset); if (f2fs_crc_valid(crc, cp_block, crc_offset)) goto invalid_cp1; cur_version = le64_to_cpu(cp_block->checkpoint_ver); if (cur_version == pre_version) { *version = cur_version; free(cp_page_2); return cp_page_1; } invalid_cp2: free(cp_page_2); invalid_cp1: free(cp_page_1); return NULL; } int get_valid_checkpoint(struct f2fs_sb_info *sbi) { struct f2fs_super_block *raw_sb = sbi->raw_super; void *cp1, *cp2, *cur_page; unsigned long blk_size = sbi->blocksize; unsigned long long cp1_version = 0, cp2_version = 0; unsigned long long cp_start_blk_no; sbi->ckpt = malloc(blk_size); if (!sbi->ckpt) return -ENOMEM; /* * Finding out valid cp block involves read both * sets( cp pack1 and cp pack 2) */ cp_start_blk_no = le32_to_cpu(raw_sb->cp_blkaddr); cp1 = validate_checkpoint(sbi, cp_start_blk_no, &cp1_version); /* The second checkpoint pack should start at the next segment */ cp_start_blk_no += 1 << le32_to_cpu(raw_sb->log_blocks_per_seg); cp2 = validate_checkpoint(sbi, cp_start_blk_no, &cp2_version); if (cp1 && cp2) { if (ver_after(cp2_version, cp1_version)) cur_page = cp2; else cur_page = cp1; } else if (cp1) { cur_page = cp1; } else if (cp2) { cur_page = cp2; } else { free(cp1); free(cp2); goto fail_no_cp; } memcpy(sbi->ckpt, cur_page, blk_size); free(cp1); free(cp2); return 0; fail_no_cp: free(sbi->ckpt); return -EINVAL; } int sanity_check_ckpt(struct f2fs_sb_info *sbi) { unsigned int total, fsmeta; struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi); struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); total = le32_to_cpu(raw_super->segment_count); fsmeta = le32_to_cpu(raw_super->segment_count_ckpt); fsmeta += le32_to_cpu(raw_super->segment_count_sit); fsmeta += le32_to_cpu(raw_super->segment_count_nat); fsmeta += le32_to_cpu(ckpt->rsvd_segment_count); fsmeta += le32_to_cpu(raw_super->segment_count_ssa); if (fsmeta >= total) return 1; return 0; } int init_node_manager(struct f2fs_sb_info *sbi) { struct f2fs_super_block *sb_raw = F2FS_RAW_SUPER(sbi); struct f2fs_nm_info *nm_i = NM_I(sbi); unsigned char *version_bitmap; unsigned int nat_segs, nat_blocks; nm_i->nat_blkaddr = le32_to_cpu(sb_raw->nat_blkaddr); /* segment_count_nat includes pair segment so divide to 2. */ nat_segs = le32_to_cpu(sb_raw->segment_count_nat) >> 1; nat_blocks = nat_segs << le32_to_cpu(sb_raw->log_blocks_per_seg); nm_i->max_nid = NAT_ENTRY_PER_BLOCK * nat_blocks; nm_i->fcnt = 0; nm_i->nat_cnt = 0; nm_i->init_scan_nid = le32_to_cpu(sbi->ckpt->next_free_nid); nm_i->next_scan_nid = le32_to_cpu(sbi->ckpt->next_free_nid); nm_i->bitmap_size = __bitmap_size(sbi, NAT_BITMAP); nm_i->nat_bitmap = malloc(nm_i->bitmap_size); if (!nm_i->nat_bitmap) return -ENOMEM; version_bitmap = __bitmap_ptr(sbi, NAT_BITMAP); if (!version_bitmap) return -EFAULT; /* copy version bitmap */ memcpy(nm_i->nat_bitmap, version_bitmap, nm_i->bitmap_size); return 0; } int build_node_manager(struct f2fs_sb_info *sbi) { int err; sbi->nm_info = malloc(sizeof(struct f2fs_nm_info)); if (!sbi->nm_info) return -ENOMEM; err = init_node_manager(sbi); if (err) return err; return 0; } int build_sit_info(struct f2fs_sb_info *sbi) { struct f2fs_super_block *raw_sb = F2FS_RAW_SUPER(sbi); struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); struct sit_info *sit_i; unsigned int sit_segs, start; char *src_bitmap, *dst_bitmap; unsigned int bitmap_size; sit_i = malloc(sizeof(struct sit_info)); if (!sit_i) return -ENOMEM; SM_I(sbi)->sit_info = sit_i; sit_i->sentries = calloc(TOTAL_SEGS(sbi) * sizeof(struct seg_entry), 1); for (start = 0; start < TOTAL_SEGS(sbi); start++) { sit_i->sentries[start].cur_valid_map = calloc(SIT_VBLOCK_MAP_SIZE, 1); sit_i->sentries[start].ckpt_valid_map = calloc(SIT_VBLOCK_MAP_SIZE, 1); if (!sit_i->sentries[start].cur_valid_map || !sit_i->sentries[start].ckpt_valid_map) return -ENOMEM; } sit_segs = le32_to_cpu(raw_sb->segment_count_sit) >> 1; bitmap_size = __bitmap_size(sbi, SIT_BITMAP); src_bitmap = __bitmap_ptr(sbi, SIT_BITMAP); dst_bitmap = malloc(bitmap_size); memcpy(dst_bitmap, src_bitmap, bitmap_size); sit_i->sit_base_addr = le32_to_cpu(raw_sb->sit_blkaddr); sit_i->sit_blocks = sit_segs << sbi->log_blocks_per_seg; sit_i->written_valid_blocks = le64_to_cpu(ckpt->valid_block_count); sit_i->sit_bitmap = dst_bitmap; sit_i->bitmap_size = bitmap_size; sit_i->dirty_sentries = 0; sit_i->sents_per_block = SIT_ENTRY_PER_BLOCK; sit_i->elapsed_time = le64_to_cpu(ckpt->elapsed_time); return 0; } void reset_curseg(struct f2fs_sb_info *sbi, int type, int modified) { struct curseg_info *curseg = CURSEG_I(sbi, type); curseg->segno = curseg->next_segno; curseg->zone = GET_ZONENO_FROM_SEGNO(sbi, curseg->segno); curseg->next_blkoff = 0; curseg->next_segno = NULL_SEGNO; } int read_compacted_summaries(struct f2fs_sb_info *sbi) { struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); struct curseg_info *curseg; block_t start; char *kaddr; unsigned int i, j, offset; start = start_sum_block(sbi); kaddr = (char *)malloc(PAGE_SIZE); dev_read_block(kaddr, start++); curseg = CURSEG_I(sbi, CURSEG_HOT_DATA); memcpy(&curseg->sum_blk->n_nats, kaddr, SUM_JOURNAL_SIZE); curseg = CURSEG_I(sbi, CURSEG_COLD_DATA); memcpy(&curseg->sum_blk->n_sits, kaddr + SUM_JOURNAL_SIZE, SUM_JOURNAL_SIZE); offset = 2 * SUM_JOURNAL_SIZE; for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) { unsigned short blk_off; unsigned int segno; curseg = CURSEG_I(sbi, i); segno = le32_to_cpu(ckpt->cur_data_segno[i]); blk_off = le16_to_cpu(ckpt->cur_data_blkoff[i]); curseg->next_segno = segno; reset_curseg(sbi, i, 0); curseg->alloc_type = ckpt->alloc_type[i]; curseg->next_blkoff = blk_off; if (curseg->alloc_type == SSR) blk_off = sbi->blocks_per_seg; for (j = 0; j < blk_off; j++) { struct f2fs_summary *s; s = (struct f2fs_summary *)(kaddr + offset); curseg->sum_blk->entries[j] = *s; offset += SUMMARY_SIZE; if (offset + SUMMARY_SIZE <= PAGE_CACHE_SIZE - SUM_FOOTER_SIZE) continue; memset(kaddr, 0, PAGE_SIZE); dev_read_block(kaddr, start++); offset = 0; } } free(kaddr); return 0; } int restore_node_summary(struct f2fs_sb_info *sbi, unsigned int segno, struct f2fs_summary_block *sum_blk) { struct f2fs_node *node_blk; struct f2fs_summary *sum_entry; void *page; block_t addr; int i; page = malloc(PAGE_SIZE); if (!page) return -ENOMEM; /* scan the node segment */ addr = START_BLOCK(sbi, segno); sum_entry = &sum_blk->entries[0]; for (i = 0; i < sbi->blocks_per_seg; i++, sum_entry++) { if (dev_read_block(page, addr)) goto out; node_blk = (struct f2fs_node *)page; sum_entry->nid = node_blk->footer.nid; /* do not change original value */ #if 0 sum_entry->version = 0; sum_entry->ofs_in_node = 0; #endif addr++; } out: free(page); return 0; } int read_normal_summaries(struct f2fs_sb_info *sbi, int type) { struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); struct f2fs_summary_block *sum_blk; struct curseg_info *curseg; unsigned short blk_off; unsigned int segno = 0; block_t blk_addr = 0; if (IS_DATASEG(type)) { segno = le32_to_cpu(ckpt->cur_data_segno[type]); blk_off = le16_to_cpu(ckpt->cur_data_blkoff[type - CURSEG_HOT_DATA]); if (is_set_ckpt_flags(ckpt, CP_UMOUNT_FLAG)) blk_addr = sum_blk_addr(sbi, NR_CURSEG_TYPE, type); else blk_addr = sum_blk_addr(sbi, NR_CURSEG_DATA_TYPE, type); } else { segno = le32_to_cpu(ckpt->cur_node_segno[type - CURSEG_HOT_NODE]); blk_off = le16_to_cpu(ckpt->cur_node_blkoff[type - CURSEG_HOT_NODE]); if (is_set_ckpt_flags(ckpt, CP_UMOUNT_FLAG)) blk_addr = sum_blk_addr(sbi, NR_CURSEG_NODE_TYPE, type - CURSEG_HOT_NODE); else blk_addr = GET_SUM_BLKADDR(sbi, segno); } sum_blk = (struct f2fs_summary_block *)malloc(PAGE_SIZE); dev_read_block(sum_blk, blk_addr); if (IS_NODESEG(type)) { if (is_set_ckpt_flags(ckpt, CP_UMOUNT_FLAG)) { struct f2fs_summary *sum_entry = &sum_blk->entries[0]; int i; for (i = 0; i < sbi->blocks_per_seg; i++, sum_entry++) { /* do not change original value */ #if 0 sum_entry->version = 0; sum_entry->ofs_in_node = 0; #endif } } else { if (restore_node_summary(sbi, segno, sum_blk)) { free(sum_blk); return -EINVAL; } } } curseg = CURSEG_I(sbi, type); memcpy(curseg->sum_blk, sum_blk, PAGE_CACHE_SIZE); curseg->next_segno = segno; reset_curseg(sbi, type, 0); curseg->alloc_type = ckpt->alloc_type[type]; curseg->next_blkoff = blk_off; free(sum_blk); return 0; } int restore_curseg_summaries(struct f2fs_sb_info *sbi) { int type = CURSEG_HOT_DATA; if (is_set_ckpt_flags(F2FS_CKPT(sbi), CP_COMPACT_SUM_FLAG)) { if (read_compacted_summaries(sbi)) return -EINVAL; type = CURSEG_HOT_NODE; } for (; type <= CURSEG_COLD_NODE; type++) { if (read_normal_summaries(sbi, type)) return -EINVAL; } return 0; } int build_curseg(struct f2fs_sb_info *sbi) { struct curseg_info *array; int i; array = malloc(sizeof(*array) * NR_CURSEG_TYPE); SM_I(sbi)->curseg_array = array; for (i = 0; i < NR_CURSEG_TYPE; i++) { array[i].sum_blk = malloc(PAGE_CACHE_SIZE); if (!array[i].sum_blk) return -ENOMEM; array[i].segno = NULL_SEGNO; array[i].next_blkoff = 0; } return restore_curseg_summaries(sbi); } inline void check_seg_range(struct f2fs_sb_info *sbi, unsigned int segno) { unsigned int end_segno = SM_I(sbi)->segment_count - 1; ASSERT(segno <= end_segno); } struct f2fs_sit_block *get_current_sit_page(struct f2fs_sb_info *sbi, unsigned int segno) { struct sit_info *sit_i = SIT_I(sbi); unsigned int offset = SIT_BLOCK_OFFSET(sit_i, segno); block_t blk_addr = sit_i->sit_base_addr + offset; struct f2fs_sit_block *sit_blk = calloc(BLOCK_SZ, 1); check_seg_range(sbi, segno); /* calculate sit block address */ if (f2fs_test_bit(offset, sit_i->sit_bitmap)) blk_addr += sit_i->sit_blocks; dev_read_block(sit_blk, blk_addr); return sit_blk; } void check_block_count(struct f2fs_sb_info *sbi, int segno, struct f2fs_sit_entry *raw_sit) { struct f2fs_sm_info *sm_info = SM_I(sbi); unsigned int end_segno = sm_info->segment_count - 1; int valid_blocks = 0; int i; /* check segment usage */ ASSERT(GET_SIT_VBLOCKS(raw_sit) <= sbi->blocks_per_seg); /* check boundary of a given segment number */ ASSERT(segno <= end_segno); /* check bitmap with valid block count */ for (i = 0; i < sbi->blocks_per_seg; i++) if (f2fs_test_bit(i, (char *)raw_sit->valid_map)) valid_blocks++; ASSERT(GET_SIT_VBLOCKS(raw_sit) == valid_blocks); } void seg_info_from_raw_sit(struct seg_entry *se, struct f2fs_sit_entry *raw_sit) { se->valid_blocks = GET_SIT_VBLOCKS(raw_sit); se->ckpt_valid_blocks = GET_SIT_VBLOCKS(raw_sit); memcpy(se->cur_valid_map, raw_sit->valid_map, SIT_VBLOCK_MAP_SIZE); memcpy(se->ckpt_valid_map, raw_sit->valid_map, SIT_VBLOCK_MAP_SIZE); se->type = GET_SIT_TYPE(raw_sit); se->mtime = le64_to_cpu(raw_sit->mtime); } struct seg_entry *get_seg_entry(struct f2fs_sb_info *sbi, unsigned int segno) { struct sit_info *sit_i = SIT_I(sbi); return &sit_i->sentries[segno]; } int get_sum_block(struct f2fs_sb_info *sbi, unsigned int segno, struct f2fs_summary_block *sum_blk) { struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); struct curseg_info *curseg; int type, ret; u64 ssa_blk; ssa_blk = GET_SUM_BLKADDR(sbi, segno); for (type = 0; type < NR_CURSEG_NODE_TYPE; type++) { if (segno == ckpt->cur_node_segno[type]) { curseg = CURSEG_I(sbi, CURSEG_HOT_NODE + type); memcpy(sum_blk, curseg->sum_blk, BLOCK_SZ); return SEG_TYPE_CUR_NODE; /* current node seg was not stored */ } } for (type = 0; type < NR_CURSEG_DATA_TYPE; type++) { if (segno == ckpt->cur_data_segno[type]) { curseg = CURSEG_I(sbi, type); memcpy(sum_blk, curseg->sum_blk, BLOCK_SZ); ASSERT(!IS_SUM_NODE_SEG(sum_blk->footer)); DBG(2, "segno [0x%x] is current data seg[0x%x]\n", segno, type); return SEG_TYPE_CUR_DATA; /* current data seg was not stored */ } } ret = dev_read_block(sum_blk, ssa_blk); ASSERT(ret >= 0); if (IS_SUM_NODE_SEG(sum_blk->footer)) return SEG_TYPE_NODE; else return SEG_TYPE_DATA; } int get_sum_entry(struct f2fs_sb_info *sbi, u32 blk_addr, struct f2fs_summary *sum_entry) { struct f2fs_summary_block *sum_blk; u32 segno, offset; int ret; segno = GET_SEGNO(sbi, blk_addr); offset = OFFSET_IN_SEG(sbi, blk_addr); sum_blk = calloc(BLOCK_SZ, 1); ret = get_sum_block(sbi, segno, sum_blk); memcpy(sum_entry, &(sum_blk->entries[offset]), sizeof(struct f2fs_summary)); free(sum_blk); return ret; } int get_nat_entry(struct f2fs_sb_info *sbi, nid_t nid, struct f2fs_nat_entry *raw_nat) { struct f2fs_fsck *fsck = F2FS_FSCK(sbi); struct f2fs_nm_info *nm_i = NM_I(sbi); struct f2fs_nat_block *nat_block; pgoff_t block_off; pgoff_t block_addr; int seg_off, entry_off; int ret; if ((nid / NAT_ENTRY_PER_BLOCK) > fsck->nr_nat_entries) { DBG(0, "nid is over max nid\n"); return -EINVAL; } if (lookup_nat_in_journal(sbi, nid, raw_nat) >= 0) return 0; nat_block = (struct f2fs_nat_block *)calloc(BLOCK_SZ, 1); block_off = nid / NAT_ENTRY_PER_BLOCK; entry_off = nid % NAT_ENTRY_PER_BLOCK; seg_off = block_off >> sbi->log_blocks_per_seg; block_addr = (pgoff_t)(nm_i->nat_blkaddr + (seg_off << sbi->log_blocks_per_seg << 1) + (block_off & ((1 << sbi->log_blocks_per_seg) - 1))); if (f2fs_test_bit(block_off, nm_i->nat_bitmap)) block_addr += sbi->blocks_per_seg; ret = dev_read_block(nat_block, block_addr); ASSERT(ret >= 0); memcpy(raw_nat, &nat_block->entries[entry_off], sizeof(struct f2fs_nat_entry)); free(nat_block); return 0; } int get_node_info(struct f2fs_sb_info *sbi, nid_t nid, struct node_info *ni) { struct f2fs_nat_entry raw_nat; int ret; ret = get_nat_entry(sbi, nid, &raw_nat); ni->nid = nid; node_info_from_raw_nat(ni, &raw_nat); return ret; } void build_sit_entries(struct f2fs_sb_info *sbi) { struct sit_info *sit_i = SIT_I(sbi); struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_COLD_DATA); struct f2fs_summary_block *sum = curseg->sum_blk; unsigned int segno; for (segno = 0; segno < TOTAL_SEGS(sbi); segno++) { struct seg_entry *se = &sit_i->sentries[segno]; struct f2fs_sit_block *sit_blk; struct f2fs_sit_entry sit; int i; for (i = 0; i < sits_in_cursum(sum); i++) { if (le32_to_cpu(segno_in_journal(sum, i)) == segno) { sit = sit_in_journal(sum, i); goto got_it; } } sit_blk = get_current_sit_page(sbi, segno); sit = sit_blk->entries[SIT_ENTRY_OFFSET(sit_i, segno)]; free(sit_blk); got_it: check_block_count(sbi, segno, &sit); seg_info_from_raw_sit(se, &sit); } } int build_segment_manager(struct f2fs_sb_info *sbi) { struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi); struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); struct f2fs_sm_info *sm_info; sm_info = malloc(sizeof(struct f2fs_sm_info)); if (!sm_info) return -ENOMEM; /* init sm info */ sbi->sm_info = sm_info; sm_info->seg0_blkaddr = le32_to_cpu(raw_super->segment0_blkaddr); sm_info->main_blkaddr = le32_to_cpu(raw_super->main_blkaddr); sm_info->segment_count = le32_to_cpu(raw_super->segment_count); sm_info->reserved_segments = le32_to_cpu(ckpt->rsvd_segment_count); sm_info->ovp_segments = le32_to_cpu(ckpt->overprov_segment_count); sm_info->main_segments = le32_to_cpu(raw_super->segment_count_main); sm_info->ssa_blkaddr = le32_to_cpu(raw_super->ssa_blkaddr); build_sit_info(sbi); build_curseg(sbi); build_sit_entries(sbi); return 0; } int build_sit_area_bitmap(struct f2fs_sb_info *sbi) { struct f2fs_fsck *fsck = F2FS_FSCK(sbi); struct f2fs_sm_info *sm_i = SM_I(sbi); int segno = 0, j = 0; char *ptr = NULL; u32 sum_vblocks = 0; u32 free_segs = 0; u32 vblocks = 0; struct seg_entry *se; fsck->sit_area_bitmap_sz = sm_i->main_segments * SIT_VBLOCK_MAP_SIZE; fsck->sit_area_bitmap = calloc(1, fsck->sit_area_bitmap_sz); ptr = fsck->sit_area_bitmap; ASSERT(fsck->sit_area_bitmap_sz == fsck->main_area_bitmap_sz); for (segno = 0; segno < sm_i->main_segments; segno++) { se = get_seg_entry(sbi, segno); memcpy(ptr, se->cur_valid_map, SIT_VBLOCK_MAP_SIZE); ptr += SIT_VBLOCK_MAP_SIZE; vblocks = 0; for (j = 0; j < SIT_VBLOCK_MAP_SIZE; j++) { vblocks += get_bits_in_byte(se->cur_valid_map[j]); } ASSERT(vblocks == se->valid_blocks); if (se->valid_blocks == 0x0) { if (sbi->ckpt->cur_node_segno[0] == segno || sbi->ckpt->cur_data_segno[0] == segno || sbi->ckpt->cur_node_segno[1] == segno || sbi->ckpt->cur_data_segno[1] == segno || sbi->ckpt->cur_node_segno[2] == segno || sbi->ckpt->cur_data_segno[2] == segno) { continue; } else { free_segs++; } } else { ASSERT(se->valid_blocks <= 512); sum_vblocks += se->valid_blocks; } } fsck->chk.sit_valid_blocks = sum_vblocks; fsck->chk.sit_free_segs = free_segs; DBG(1, " build SIT bitmap done: Blocks [0x%x : %d] Free Segs [0x%x : %d]\n\n", sum_vblocks, sum_vblocks, free_segs, free_segs); return 0; } int lookup_nat_in_journal(struct f2fs_sb_info *sbi, u32 nid, struct f2fs_nat_entry *raw_nat) { struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA); struct f2fs_summary_block *sum = curseg->sum_blk; int i = 0; for (i = 0; i < nats_in_cursum(sum); i++) { if (le32_to_cpu(nid_in_journal(sum, i)) == nid) { memcpy(raw_nat, &nat_in_journal(sum, i), sizeof(struct f2fs_nat_entry)); DBG(3, "==> Found nid [0x%x] in nat cache\n", nid); return i; } } return -1; } void build_nat_area_bitmap(struct f2fs_sb_info *sbi) { struct f2fs_fsck *fsck = F2FS_FSCK(sbi); struct f2fs_super_block *raw_sb = F2FS_RAW_SUPER(sbi); struct f2fs_nm_info *nm_i = NM_I(sbi); struct f2fs_nat_block *nat_block; u32 nid, nr_nat_blks; pgoff_t block_off; pgoff_t block_addr; int seg_off; int ret, i; nat_block = (struct f2fs_nat_block *)calloc(BLOCK_SZ, 1); /* Alloc & build nat entry bitmap */ nr_nat_blks = (le32_to_cpu(raw_sb->segment_count_nat) / 2) << sbi->log_blocks_per_seg; fsck->nr_nat_entries = nr_nat_blks * NAT_ENTRY_PER_BLOCK; fsck->nat_area_bitmap_sz = (fsck->nr_nat_entries + 7) / 8; fsck->nat_area_bitmap = calloc(fsck->nat_area_bitmap_sz, 1); ASSERT(fsck->nat_area_bitmap != NULL); for (block_off = 0; block_off < nr_nat_blks; block_off++) { seg_off = block_off >> sbi->log_blocks_per_seg; block_addr = (pgoff_t)(nm_i->nat_blkaddr + (seg_off << sbi->log_blocks_per_seg << 1) + (block_off & ((1 << sbi->log_blocks_per_seg) - 1))); if (f2fs_test_bit(block_off, nm_i->nat_bitmap)) block_addr += sbi->blocks_per_seg; ret = dev_read_block(nat_block, block_addr); ASSERT(ret >= 0); nid = block_off * NAT_ENTRY_PER_BLOCK; for (i = 0; i < NAT_ENTRY_PER_BLOCK; i++) { struct f2fs_nat_entry raw_nat; struct node_info ni; ni.nid = nid + i; if ((nid + i) == F2FS_NODE_INO(sbi) || (nid + i) == F2FS_META_INO(sbi)) { ASSERT(nat_block->entries[i].block_addr != 0x0); continue; } if (lookup_nat_in_journal(sbi, nid + i, &raw_nat) >= 0) { node_info_from_raw_nat(&ni, &raw_nat); if (ni.blk_addr != 0x0) { f2fs_set_bit(nid + i, fsck->nat_area_bitmap); fsck->chk.valid_nat_entry_cnt++; DBG(3, "nid[0x%x] in nat cache\n", nid + i); } } else { node_info_from_raw_nat(&ni, &nat_block->entries[i]); if (ni.blk_addr != 0) { ASSERT(nid + i != 0x0); DBG(3, "nid[0x%8x] in nat entry [0x%16x] [0x%8x]\n", nid + i, ni.blk_addr, ni.ino); f2fs_set_bit(nid + i, fsck->nat_area_bitmap); fsck->chk.valid_nat_entry_cnt++; } } } } free(nat_block); DBG(1, "valid nat entries (block_addr != 0x0) [0x%8x : %u]\n", fsck->chk.valid_nat_entry_cnt, fsck->chk.valid_nat_entry_cnt); } int f2fs_do_mount(struct f2fs_sb_info *sbi) { int ret; sbi->active_logs = NR_CURSEG_TYPE; ret = validate_super_block(sbi, 0); if (ret) { ret = validate_super_block(sbi, 1); if (ret) return -1; } print_raw_sb_info(sbi); init_sb_info(sbi); ret = get_valid_checkpoint(sbi); if (ret) { ERR_MSG("Can't find valid checkpoint\n"); return -1; } if (sanity_check_ckpt(sbi)) { ERR_MSG("Checkpoint is polluted\n"); return -1; } print_ckpt_info(sbi); sbi->total_valid_node_count = le32_to_cpu(sbi->ckpt->valid_node_count); sbi->total_valid_inode_count = le32_to_cpu(sbi->ckpt->valid_inode_count); sbi->user_block_count = le64_to_cpu(sbi->ckpt->user_block_count); sbi->total_valid_block_count = le64_to_cpu(sbi->ckpt->valid_block_count); sbi->last_valid_block_count = sbi->total_valid_block_count; sbi->alloc_valid_block_count = 0; if (build_segment_manager(sbi)) { ERR_MSG("build_segment_manager failed\n"); return -1; } if (build_node_manager(sbi)) { ERR_MSG("build_segment_manager failed\n"); return -1; } return ret; } void f2fs_do_umount(struct f2fs_sb_info *sbi) { struct sit_info *sit_i = SIT_I(sbi); struct f2fs_sm_info *sm_i = SM_I(sbi); struct f2fs_nm_info *nm_i = NM_I(sbi); int i; /* free nm_info */ free(nm_i->nat_bitmap); free(sbi->nm_info); /* free sit_info */ for (i = 0; i < TOTAL_SEGS(sbi); i++) { free(sit_i->sentries[i].cur_valid_map); free(sit_i->sentries[i].ckpt_valid_map); } free(sit_i->sit_bitmap); free(sm_i->sit_info); /* free sm_info */ for (i = 0; i < NR_CURSEG_TYPE; i++) free(sm_i->curseg_array[i].sum_blk); free(sm_i->curseg_array); free(sbi->sm_info); free(sbi->ckpt); free(sbi->raw_super); } partclone-0.2.86/src/f2fsclone.c000066400000000000000000000077041262102574200164230ustar00rootroot00000000000000/** * f2fsclone.c - part of Partclone project * * Copyright (c) 2014~ Thomas Tsai * * read f2fs super block and bitmap * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ #include #include #include "f2fs/fsck.h" #include "partclone.h" #include "f2fsclone.h" #include "progress.h" #include "fs_common.h" char *EXECNAME = "partclone.f2fs"; extern fs_cmd_opt fs_opt; struct f2fs_fsck gfsck = { .sbi.fsck = &gfsck, }; struct f2fs_sb_info *sbi = &gfsck.sbi; extern struct f2fs_configuration config; /// open device static void fs_open(char* device){ int ret = 0; f2fs_init_configuration(&config); config.device_name = device; if (f2fs_dev_is_umounted(&config) < 0) log_mesg(0, 1, 1, fs_opt.debug, "%s: f2fs_dev_is_umounted\n", __FILE__); /* Get device */ if (f2fs_get_device_info(&config) < 0) log_mesg(0, 1, 1, fs_opt.debug, "%s: f2fs_get_device_info fail\n", __FILE__); if (f2fs_do_mount(sbi) < 0) log_mesg(0, 1, 1, fs_opt.debug, "%s: f2fs_do_mount fail\n", __FILE__); ret = fsck_init(sbi); if (ret < 0) log_mesg(0, 1, 1, fs_opt.debug, "%s: fsck_init init fail\n", __FILE__); fsck_chk_orphan_node(sbi); } /// close device static void fs_close(){ fsck_free(sbi); f2fs_do_umount(sbi); } /// readbitmap - read bitmap extern void readbitmap(char* device, image_head image_hdr, unsigned long* bitmap, int pui) { off_t block = 0;; int start = 0; int bit_size = 1; unsigned long long bused, bfree; fs_open(device); struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); /// init progress progress_bar prog; /// progress_bar structure defined in progress.h progress_init(&prog, start, image_hdr.totalblock, image_hdr.totalblock, BITMAP, bit_size); /// bitmap test log_mesg(1, 0, 0, fs_opt.debug, "%s: start f2fs bitmap dump\n", __FILE__); struct f2fs_fsck *fsck = F2FS_FSCK(sbi); log_mesg(1, 0, 0, fs_opt.debug, "%s: start fsck sit\n", __FILE__); for ( block = 0; block <= sb->main_blkaddr ; block++ ){ log_mesg(2, 0, 0, fs_opt.debug, "%s: test SIT bitmap is 0x1. blk_addr[0x%x] %i\n", __FILE__, block, block); bused++; pc_set_bit(block, bitmap); log_mesg(3, 0, 0, fs_opt.debug, "%s: bitmap is used %llu", __FILE__, block); } for ( block = sb->main_blkaddr ; block <= sb->block_count ; block++ ){ log_mesg(3, 0, 0, fs_opt.debug, "%s: block = %i\n", __FILE__, block); if (f2fs_test_bit(BLKOFF_FROM_MAIN(sbi, block), fsck->sit_area_bitmap) == 0x0) { log_mesg(2, 0, 0, fs_opt.debug, "%s: test SIT bitmap is 0x0. blk_addr[0x%x] %i\n", __FILE__, block, block); pc_clear_bit(block, bitmap); bfree++; log_mesg(3, 0, 0, fs_opt.debug, "%s: bitmap is free %llu", __FILE__, block); }else{ log_mesg(2, 0, 0, fs_opt.debug, "%s: test SIT bitmap is 0x1. blk_addr[0x%x] %i\n", __FILE__, block, block); bused++; pc_set_bit(block, bitmap); log_mesg(3, 0, 0, fs_opt.debug, "%s: bitmap is used %llu", __FILE__, block); } /// update progress update_pui(&prog, block, block, 0); } fs_close(); /// update progress update_pui(&prog, 1, 1, 1); } /// read super block and write to image head extern void initial_image_hdr(char* device, image_head* image_hdr) { fs_open(device); struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); struct f2fs_checkpoint *cp = F2FS_CKPT(sbi); strncpy(image_hdr->magic, IMAGE_MAGIC, IMAGE_MAGIC_SIZE); strncpy(image_hdr->fs, f2fs_MAGIC, FS_MAGIC_SIZE); image_hdr->block_size = F2FS_BLKSIZE; image_hdr->totalblock = sb->block_count; image_hdr->usedblocks = (sb->segment_count-cp->free_segment_count)*DEFAULT_BLOCKS_PER_SEGMENT; image_hdr->device_size = config.total_sectors*config.sector_size; fs_close(); } partclone-0.2.86/src/f2fsclone.h000066400000000000000000000012101262102574200164120ustar00rootroot00000000000000/** * f2fsclone.h - part of Partclone project * * Copyright (c) 2007~ Thomas Tsai * * read reiserfs super block and bitmap * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ /// readbitmap - read bitmap extern void readbitmap(char* device, image_head image_hdr, unsigned long* bitmap, int pui); /// read super block and write to image head extern void initial_image_hdr(char* device, image_head* image_hdr); partclone-0.2.86/src/fatclone.c000066400000000000000000000425401262102574200163320ustar00rootroot00000000000000/** fatclone.c - part of Partclone project * * Copyright (c) 2007~ Thomas Tsai * * read FAT12/16/32 super block and bitmap * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ #include #include #include #include #include #include #include #include #include "partclone.h" #include "fatclone.h" #include "progress.h" #include "fs_common.h" struct FatBootSector fat_sb; struct FatFsInfo fatfs_info; int ret; int FS; char *fat_type = "FATXX"; char *EXECNAME = "partclone.fat"; extern fs_cmd_opt fs_opt; #define FAT12_THRESHOLD 4085 #define FAT16_THRESHOLD 65525 /* Unaligned fields must first be accessed byte-wise */ #define GET_UNALIGNED_W(f) ( (uint16_t)f[0] | ((uint16_t)f[1]<<8) ) /* don't divide by zero */ #define ROUND_TO_MULTIPLE(n,m) ((n) && (m) ? (n)+(m)-1-((n)-1)%(m) : 0) #define MSDOS_DIR_BITS 5 /* log2(sizeof(struct msdos_dir_entry)) */ static unsigned long long get_used_block(); /// get fet type static void get_fat_type(){ off_t total_sectors; off_t logical_sector_size; off_t data_start; off_t data_size; off_t clusters; off_t root_start; unsigned int root_entries; /// fix, 1. make sure fasectoe. the method shoud be check again if ((fat_sb.u.fat16.ext_signature == 0x29) || (fat_sb.fat_length && !fat_sb.u.fat32.fat_length)){ total_sectors = get_total_sector(); logical_sector_size = fat_sb.sector_size; root_start = (fat_sb.reserved + fat_sb.fats * fat_sb.fat_length) * logical_sector_size; root_entries = fat_sb.dir_entries; data_start = root_start + ROUND_TO_MULTIPLE(root_entries <= FAT12_THRESHOLD){ FS = FAT_16; fat_type = "FAT16"; log_mesg(2, 0, 0, fs_opt.debug, "%s: FAT Type : FAT 16(clusters %lu)\n", __FILE__, clusters); if (clusters >= FAT16_THRESHOLD) log_mesg(2, 0, 0, fs_opt.debug, "Too many clusters (%lu) for FAT16 filesystem.", clusters); } else { FS = FAT_12; fat_type = "FAT12"; log_mesg(2, 0, 0, fs_opt.debug, "%s: FAT Type : FAT 12(clusters %lu)\n", __FILE__, clusters); } } else if ((fat_sb.u.fat32.fat_name[4] == '2')||(!fat_sb.fat_length && fat_sb.u.fat32.fat_length)){ FS = FAT_32; fat_type = "FAT32"; log_mesg(2, 0, 0, fs_opt.debug, "%s: FAT Type : FAT 32\n", __FILE__); } else { log_mesg(0, 1, 1, fs_opt.debug, "%s: Unknown fat type!!\n", __FILE__); } log_mesg(2, 0, 0, fs_opt.debug, "%s: FS = %i\n", __FILE__, FS); } /// return total sectors unsigned long long get_total_sector() { unsigned long long total_sector = 0; /// get fat sectors if (fat_sb.sectors != 0) total_sector = (unsigned long long)fat_sb.sectors; else total_sector = (unsigned long long)fat_sb.sector_count; return total_sector; } ///return sec_per_fat unsigned long long get_sec_per_fat() { unsigned long long sec_per_fat = 0; /// get fat length if(fat_sb.fat_length != 0) sec_per_fat = fat_sb.fat_length; else sec_per_fat = fat_sb.u.fat32.fat_length; return sec_per_fat; } ///return root sec unsigned long long get_root_sec() { unsigned long long root_sec = 0; root_sec = ((fat_sb.dir_entries * 32) + fat_sb.sector_size - 1) / fat_sb.sector_size; return root_sec; } /// return cluster count unsigned long long get_cluster_count() { unsigned long long data_sec = 0; unsigned long long cluster_count = 0; unsigned long long total_sector = get_total_sector(); unsigned long long root_sec = get_root_sec(); unsigned long long sec_per_fat = get_sec_per_fat(); data_sec = total_sector - ( fat_sb.reserved + (fat_sb.fats * sec_per_fat) + root_sec); cluster_count = data_sec / fat_sb.cluster_size; return cluster_count; } /// check fat status //return - 0 Filesystem is in valid state. //return - 1 Filesystem isn't in valid state. //return - 2 other error. extern int check_fat_status(){ int rd = 0; uint16_t Fat16_Entry; uint32_t Fat32_Entry; int fs_error = 2; int fs_good = 0; int fs_bad = 1; /// fix. 1.check ret; if (FS == FAT_16){ /// FAT[0] contains BPB_Media code rd = read(ret, &Fat16_Entry, sizeof(Fat16_Entry)); log_mesg(2, 0, 0, fs_opt.debug, "%s: Media %x\n", __FILE__, Fat16_Entry); if (rd == -1) log_mesg(2, 0, 0, fs_opt.debug, "%s: read Fat16_Entry error\n", __FILE__); /// FAT[1] is set for FAT16/FAT32 for dirty/error volume flag rd = read(ret, &Fat16_Entry, sizeof(Fat16_Entry)); if (rd == -1) log_mesg(2, 0, 0, fs_opt.debug, "%s: read Fat16_Entry error\n", __FILE__); if (Fat16_Entry & 0x8000) log_mesg(2, 0, 0, fs_opt.debug, "%s: Volume clean!\n", __FILE__); else return fs_bad; if (Fat16_Entry & 0x4000) log_mesg(2, 0, 0, fs_opt.debug, "%s: I/O correct!\n", __FILE__); else return fs_error; } else if (FS == FAT_32) { /// FAT[0] contains BPB_Media rd = read(ret, &Fat32_Entry, sizeof(Fat32_Entry)); if (rd == -1) log_mesg(2, 0, 0, fs_opt.debug, "%s: read Fat32_Entry error\n", __FILE__); /// FAT[1] is set for FAT16/FAT32 for dirty volume flag rd = read(ret, &Fat32_Entry, sizeof(Fat32_Entry)); if (rd == -1) log_mesg(2, 0, 0, fs_opt.debug, "%s: read Fat32_Entry error\n", __FILE__); if (Fat32_Entry & 0x08000000) log_mesg(2, 0, 0, fs_opt.debug, "%s: Volume clean!\n", __FILE__); else return fs_bad; if (Fat32_Entry & 0x04000000) log_mesg(2, 0, 0, fs_opt.debug, "%s: I/O correct!\n", __FILE__); else return fs_error; } else if (FS == FAT_12){ /// FAT[0] contains BPB_Media code rd = read(ret, &Fat16_Entry, sizeof(Fat16_Entry)); log_mesg(2, 0, 0, fs_opt.debug, "%s: Media %x\n", __FILE__, Fat16_Entry); if (rd == -1) log_mesg(2, 0, 0, fs_opt.debug, "%s: read Fat12_Entry error\n", __FILE__); rd = read(ret, &Fat16_Entry, sizeof(Fat16_Entry)); } else log_mesg(2, 0, 0, fs_opt.debug, "%s: ERR_WRONG_FS\n", __FILE__); return fs_good; } /// mark reserved sectors as used static unsigned long long mark_reserved_sectors(unsigned long* fat_bitmap, unsigned long long block) { unsigned long long i = 0; unsigned long long j = 0; unsigned long long sec_per_fat = 0; unsigned long long root_sec = 0; sec_per_fat = get_sec_per_fat(); root_sec = get_root_sec(); /// A) the reserved sectors are used for (i=0; i < fat_sb.reserved; i++,block++) pc_set_bit(block, fat_bitmap); /// B) the FAT tables are on used sectors for (j=0; j < fat_sb.fats; j++) for (i=0; i < sec_per_fat ; i++,block++) pc_set_bit(block, fat_bitmap); /// C) The rootdirectory is on used sectors if (root_sec > 0) /// no rootdir sectors on FAT32 for (i=0; i < root_sec; i++,block++) pc_set_bit(block, fat_bitmap); return block; } /// open device static void fs_open(char* device) { char *buffer; log_mesg(2, 0, 0, fs_opt.debug, "%s: open device\n", __FILE__); ret = open(device, O_RDONLY); buffer = (char*)malloc(sizeof(FatBootSector)); if(buffer == NULL){ log_mesg(0, 1, 1, fs_opt.debug, "%s, %i, ERROR:%s", __func__, __LINE__, strerror(errno)); } if(read (ret, buffer, sizeof(FatBootSector)) != sizeof(FatBootSector)) log_mesg(0, 1, 1, fs_opt.debug, "%s, %i, ERROR:%s", __func__, __LINE__, strerror(errno)); memcpy(&fat_sb, buffer, sizeof(FatBootSector)); free(buffer); buffer = (char*)malloc(sizeof(FatFsInfo)); if(buffer == NULL){ log_mesg(0, 1, 1, fs_opt.debug, "%s, %i, ERROR:%s", __func__, __LINE__, strerror(errno)); } if (read(ret, &fatfs_info, sizeof(FatFsInfo)) != sizeof(FatFsInfo)) log_mesg(0, 1, 1, fs_opt.debug, "%s, %i, ERROR:%s", __func__, __LINE__, strerror(errno)); memcpy(&fatfs_info, buffer, sizeof(FatFsInfo)); free(buffer); log_mesg(2, 0, 0, fs_opt.debug, "%s: open device down\n", __FILE__); } /// close device static void fs_close() { close(ret); } /// check per FAT32 entry unsigned long long check_fat32_entry(unsigned long* fat_bitmap, unsigned long long block, unsigned long long* bfree, unsigned long long* bused, unsigned long long* DamagedClusters) { uint32_t Fat32_Entry = 0; int rd = 0; unsigned long long i = 0; rd = read(ret, &Fat32_Entry, sizeof(Fat32_Entry)); if (rd == -1) log_mesg(2, 0, 0, fs_opt.debug, "%s: read Fat32_Entry error\n", __FILE__); if (Fat32_Entry == 0x0FFFFFF7) { /// bad FAT32 cluster DamagedClusters++; log_mesg(2, 0, 0, fs_opt.debug, "%s: bad sec %llu\n", __FILE__, block); for (i=0; i < fat_sb.cluster_size; i++,block++) pc_clear_bit(block, fat_bitmap); } else if (Fat32_Entry == 0x0000){ /// free bfree++; for (i=0; i < fat_sb.cluster_size; i++,block++) pc_clear_bit(block, fat_bitmap); } else { bused++; for (i=0; i < fat_sb.cluster_size; i++,block++) pc_set_bit(block, fat_bitmap); } return block; } /// check per FAT16 entry unsigned long long check_fat16_entry(unsigned long* fat_bitmap, unsigned long long block, unsigned long long* bfree, unsigned long long* bused, unsigned long long* DamagedClusters) { uint16_t Fat16_Entry = 0; int rd = 0; unsigned long long i = 0; rd = read(ret, &Fat16_Entry, sizeof(Fat16_Entry)); if (rd == -1) log_mesg(2, 0, 0, fs_opt.debug, "%s: read Fat16_Entry error\n", __FILE__); if (Fat16_Entry == 0xFFF7) { /// bad FAT16 cluster DamagedClusters++; log_mesg(2, 0, 0, fs_opt.debug, "%s: bad sec %llu\n", __FILE__, block); for (i=0; i < fat_sb.cluster_size; i++,block++) pc_clear_bit(block, fat_bitmap); } else if (Fat16_Entry == 0x0000){ /// free bfree++; for (i=0; i < fat_sb.cluster_size; i++,block++) pc_clear_bit(block, fat_bitmap); } else { bused++; for (i=0; i < fat_sb.cluster_size; i++,block++) pc_set_bit(block, fat_bitmap); } return block; } /// check per FAT12 entry unsigned long long check_fat12_entry(unsigned long* fat_bitmap, unsigned long long block, unsigned long long* bfree, unsigned long long* bused, unsigned long long* DamagedClusters) { uint16_t Fat16_Entry = 0; uint16_t Fat12_Entry = 0; int rd = 0; unsigned long long i = 0; rd = read(ret, &Fat16_Entry, sizeof(Fat16_Entry)); if (rd == -1) log_mesg(2, 0, 0, fs_opt.debug, "%s: read Fat12_Entry error\n", __FILE__); Fat12_Entry = Fat16_Entry>>4; if (Fat12_Entry == 0xFFF7) { /// bad FAT12 cluster DamagedClusters++; log_mesg(2, 0, 0, fs_opt.debug, "%s: bad sec %llu\n", __FILE__, block); for (i=0; i < fat_sb.cluster_size; i++,block++) pc_clear_bit(block, fat_bitmap); } else if (Fat12_Entry == 0x0000){ /// free bfree++; for (i=0; i < fat_sb.cluster_size; i++,block++) pc_clear_bit(block, fat_bitmap); } else { bused++; for (i=0; i < fat_sb.cluster_size; i++,block++) pc_set_bit(block, fat_bitmap); } return block; } /// read super block and write to image head extern void initial_image_hdr(char* device, image_head* image_hdr) { unsigned long long total_sector = 0; unsigned long long bused = 0; log_mesg(2, 0, 0, fs_opt.debug, "%s: initial_image start\n", __FILE__); fs_open(device); get_fat_type(); total_sector = get_total_sector(); bused = get_used_block();//so I need calculate by myself. strncpy(image_hdr->magic, IMAGE_MAGIC, IMAGE_MAGIC_SIZE); strncpy(image_hdr->fs, fat_type, FS_MAGIC_SIZE); image_hdr->block_size = (int)fat_sb.sector_size; image_hdr->totalblock = (unsigned long long)total_sector; image_hdr->device_size = (unsigned long long)(total_sector * image_hdr->block_size); image_hdr->usedblocks = (unsigned long long)bused; log_mesg(2, 0, 0, fs_opt.debug, "%s: Block Size:%i\n", __FILE__, image_hdr->block_size); log_mesg(2, 0, 0, fs_opt.debug, "%s: Total Blocks:%llu\n", __FILE__, image_hdr->totalblock); log_mesg(2, 0, 0, fs_opt.debug, "%s: Used Blocks:%llu\n", __FILE__, image_hdr->usedblocks); log_mesg(2, 0, 0, fs_opt.debug, "%s: Device Size:%llu\n", __FILE__, image_hdr->device_size); fs_close(); log_mesg(2, 0, 0, fs_opt.debug, "%s: initial_image down\n", __FILE__); } /// readbitmap - read and check bitmap extern void readbitmap(char* device, image_head image_hdr, unsigned long* bitmap, int pui) { unsigned long long i = 0; int fat_stat = 0; unsigned long long block = 0, bfree = 0, bused = 0, DamagedClusters = 0; unsigned long long cluster_count = 0; unsigned long long total_sector = 0; unsigned long long FatReservedBytes = 0; int start = 0; int bit_size = 1; fs_open(device); total_sector = get_total_sector(); cluster_count = get_cluster_count(); /// init progress progress_bar prog; /// progress_bar structure defined in progress.h progress_init(&prog, start, cluster_count, image_hdr.totalblock, BITMAP, bit_size); /// init bitmap memset(bitmap, 0xFF, sizeof(unsigned long)*LONGS(total_sector)); /// A) B) C) block = mark_reserved_sectors(bitmap, block); /// D) The clusters FatReservedBytes = fat_sb.sector_size * fat_sb.reserved; /// The first cluster will be seek lseek(ret, FatReservedBytes, SEEK_SET); /// The second used to check FAT status fat_stat = check_fat_status(); if(fs_opt.ignore_fschk){ log_mesg(1, 0, 0, fs_opt.debug, "%s: Ignore filesystem check\n", __FILE__); }else{ if (fat_stat == 1) log_mesg(0, 1, 1, fs_opt.debug, "%s: Filesystem isn't in valid state. May be it is not cleanly unmounted.\n\n", __FILE__); else if (fat_stat == 2) log_mesg(0, 1, 1, fs_opt.debug, "%s: I/O error! %X\n", __FILE__); } for (i=0; i < cluster_count; i++){ /// If FAT16 if(FS == FAT_16){ block = check_fat16_entry(bitmap, block, &bfree, &bused, &DamagedClusters); } else if (FS == FAT_32){ /// FAT32 block = check_fat32_entry(bitmap, block, &bfree, &bused, &DamagedClusters); } else if (FS == FAT_12){ /// FAT12 block = check_fat12_entry(bitmap, block, &bfree, &bused, &DamagedClusters); } else log_mesg(2, 0, 0, fs_opt.debug, "%s: error fs\n", __FILE__); /// update progress update_pui(&prog, i, i, 0);//keep update } log_mesg(2, 0, 0, fs_opt.debug, "%s: done\n", __FILE__); fs_close(); /// update progress update_pui(&prog, 1, 1, 1);//finish } /// get_used_block - get FAT used blocks static unsigned long long get_used_block() { unsigned long long i = 0; int fat_stat = 0; unsigned long long block = 0, bfree = 0, bused = 0, DamagedClusters = 0; unsigned long long cluster_count = 0, total_sector = 0; unsigned long long real_back_block= 0; int FatReservedBytes = 0; unsigned long *fat_bitmap; log_mesg(2, 0, 0, fs_opt.debug, "%s: get_used_block start\n", __FILE__); total_sector = get_total_sector(); cluster_count = get_cluster_count(); fat_bitmap = (unsigned long *)calloc(sizeof(unsigned long), LONGS(total_sector)); if (fat_bitmap == NULL) log_mesg(2, 1, 1, fs_opt.debug, "%s: bitmapalloc error\n", __FILE__); memset(fat_bitmap, 0xFF, sizeof(unsigned long)*LONGS(total_sector)); /// A) B) C) block = mark_reserved_sectors(fat_bitmap, block); /// D) The clusters FatReservedBytes = fat_sb.sector_size * fat_sb.reserved; /// The first fat will be seek lseek(ret, FatReservedBytes, SEEK_SET); /// The second fat is used to check FAT status fat_stat = check_fat_status(); if (fat_stat == 1) log_mesg(0, 1, 1, fs_opt.debug, "%s: Filesystem isn't in valid state. May be it is not cleanly unmounted.\n\n", __FILE__); else if (fat_stat == 2) log_mesg(0, 1, 1, fs_opt.debug, "%s: I/O error! %X\n", __FILE__); for (i=0; i < cluster_count; i++){ /// If FAT16 if(FS == FAT_16){ block = check_fat16_entry(fat_bitmap, block, &bfree, &bused, &DamagedClusters); } else if (FS == FAT_32){ /// FAT32 block = check_fat32_entry(fat_bitmap, block, &bfree, &bused, &DamagedClusters); } else if (FS == FAT_12){ /// FAT12 block = check_fat12_entry(fat_bitmap, block, &bfree, &bused, &DamagedClusters); } else log_mesg(2, 0, 0, fs_opt.debug, "%s: error fs\n", __FILE__); } while(block < total_sector){ pc_set_bit(block, fat_bitmap); block++; } for (block = 0; block < total_sector; block++) { if (pc_test_bit(block, fat_bitmap)) { real_back_block++; } } free(fat_bitmap); log_mesg(2, 0, 0, fs_opt.debug, "%s: get_used_block down\n", __FILE__); return real_back_block; } partclone-0.2.86/src/fatclone.h000066400000000000000000000103121262102574200163270ustar00rootroot00000000000000/** * fatclone.h - part of Partclone project * * Copyright (c) 2007~ Thomas Tsai * * read hfsplus super block and bitmap * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ #include #include #include #include #include #include #define FAT_12 1 #define FAT_16 2 #define FAT_32 3 // describers the FAT Boot sector, stolen from libparted struct __attribute__ ((packed)) FatBootSector { uint8_t boot_jump[3]; /* 00: Boot strap short or near jump */ uint8_t system_id[8]; /* 03: system name */ uint16_t sector_size; /* 0b: bytes per logical sector */ uint8_t cluster_size; /* 0d: sectors/cluster */ uint16_t reserved; /* 0e: reserved sectors */ uint8_t fats; /* 10: number of FATs */ uint16_t dir_entries; /* 11: number of root directory entries */ uint16_t sectors; /* 13: if 0, total_sect supersedes */ uint8_t media; /* 15: media code */ uint16_t fat_length; /* 16: sectors/FAT for FAT12/16 */ uint16_t secs_track; /* 18: sectors per track */ uint16_t heads; /* 1a: number of heads */ uint32_t hidden; /* 1c: hidden sectors (partition start) */ uint32_t sector_count; /* 20: no. of sectors (if sectors == 0) */ union __attribute__ ((packed)) { /* FAT16 fields */ struct __attribute__ ((packed)) { uint8_t drive_num; /* 24: */ uint8_t empty_1; /* 25: */ uint8_t ext_signature; /* 26: always 0x29 */ uint32_t serial_number; /* 27: */ uint8_t volume_name [11]; /* 2b: */ uint8_t fat_name [8]; /* 36: */ uint8_t boot_code[448]; /* 3f: Boot code (or message) */ } fat16; /* FAT32 fields */ struct __attribute__ ((packed)) { uint32_t fat_length; /* 24: size of FAT in sectors */ uint16_t flags; /* 28: bit8: fat mirroring, low4: active fat */ uint16_t version; /* 2a: minor * 256 + major */ uint32_t root_dir_cluster; /* 2c: */ uint16_t info_sector; /* 30: */ uint16_t backup_sector; /* 32: */ uint8_t empty_1 [12]; /* 34: */ uint16_t drive_num; /* 40: */ uint8_t ext_signature; /* 42: always 0x29 */ uint32_t serial_number; /* 43: */ uint8_t volume_name [11]; /* 47: */ uint8_t fat_name [8]; /* 52: */ uint8_t boot_code[420]; /* 5a: Boot code (or message) */ } fat32; } u; uint16_t boot_sign; /* 1fe: always 0xAA55 */ }; typedef struct FatBootSector FatBootSector; struct FatFsInfo{ uint32_t magic; uint8_t rev[480]; uint32_t signature; uint32_t free_count; uint32_t next_free; uint32_t reserved2[3]; uint32_t trail; }; typedef struct FatFsInfo FatFsInfo; /// read super block and write to image head extern void initial_image_hdr(char* device, image_head* image_hdr); /// readbitmap - cread and heck bitmap, reference dumpe2fs extern void readbitmap(char* device, image_head image_hdr, unsigned long* bitmap, int pui); /// return total sectors unsigned long long get_total_sector(); ///return sec_per_fat unsigned long long get_sec_per_fat(); ///return root sec unsigned long long get_root_sec(); /// return cluster count unsigned long long get_cluster_count(); /// check fat statu extern int check_fat_status(); /// check per FAT32 entry unsigned long long check_fat32_entry(unsigned long* fat_bitmap, unsigned long long block, unsigned long long* bfree, unsigned long long* bused, unsigned long long* DamagedClusters); /// check per FAT16 entry unsigned long long check_fat16_entry(unsigned long* fat_bitmap, unsigned long long block, unsigned long long* bfree, unsigned long long* bused, unsigned long long* DamagedClusters); partclone-0.2.86/src/fs_common.h000066400000000000000000000002071262102574200165160ustar00rootroot00000000000000#include struct fs_cmd_opt { int debug; int ignore_fschk; int force; }; typedef struct fs_cmd_opt fs_cmd_opt; partclone-0.2.86/src/fstype.c000066400000000000000000000032751262102574200160530ustar00rootroot00000000000000#include #include //#include vmfs_fs_t *fs; vmfs_volume_t *vol; vmfs_dir_t *root_dir; /// open device static int pvmfs_fs_open(char* device){ vmfs_flags_t flags; char *mdev[] = {device, NULL}; vmfs_host_init(); flags.packed = 0; flags.allow_missing_extents = 1; #ifdef VMFS5_ZLA_BASE if (!(fs = vmfs_fs_open(mdev, flags))) { fprintf(stderr, "type: Unable to open volume (vmfs5).\n"); return 1; } vol = vmfs_vol_open(device, flags); #else vmfs_lvm_t *lvm; if (!(lvm = vmfs_lvm_create(flags))) { fprintf(stderr, "Unable to create LVM structure\n"); return 1; } vol = vmfs_vol_open(device, flags); if (vmfs_lvm_add_extent(lvm, vol) == -1) { fprintf(stderr, "Unable to open device/file \"%s\".\n", device); return 1; } if (!(fs = vmfs_fs_create(lvm))) { fprintf(stderr, "Unable to open filesystem\n"); return 1; } if (vmfs_fs_open(fs) == -1) { fprintf(stderr, "type: Unable to open volume.\n"); return 1; } #endif if (!(root_dir = vmfs_dir_open_from_blkid(fs,VMFS_BLK_FD_BUILD(0,0,0)))) { fprintf(stderr, "Unable to open root directory\n"); return 1; } return 0; } /// close device static void pvmfs_vmfs_close(){ vmfs_dir_close(root_dir); vmfs_fs_close(fs); } int main (int argc, char **argv){ char* source; /// source data int ret; if( !argv[1]) { fprintf(stderr, "Please give the device name.\n"); return 1; } source=argv[1]; ret = pvmfs_fs_open(source); if(ret == 0){ fprintf(stdout, "TYPE=\"vmfs%i\"\n", vol->vol_info.version); }else{ fprintf(stderr, "error exit\n"); return 1; } pvmfs_vmfs_close(); return 0; } partclone-0.2.86/src/gettext.h000066400000000000000000000221711262102574200162260ustar00rootroot00000000000000/* Convenience header for conditional use of GNU . Copyright (C) 1995-1998, 2000-2002, 2004-2006 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _LIBGETTEXT_H #define _LIBGETTEXT_H 1 /* NLS can be disabled through the configure --disable-nls option. */ #if ENABLE_NLS /* Get declarations of GNU message catalog functions. */ # include /* You can set the DEFAULT_TEXT_DOMAIN macro to specify the domain used by the gettext() and ngettext() macros. This is an alternative to calling textdomain(), and is useful for libraries. */ # ifdef DEFAULT_TEXT_DOMAIN # undef gettext # define gettext(Msgid) \ dgettext (DEFAULT_TEXT_DOMAIN, Msgid) # undef ngettext # define ngettext(Msgid1, Msgid2, N) \ dngettext (DEFAULT_TEXT_DOMAIN, Msgid1, Msgid2, N) # endif #else /* Solaris /usr/include/locale.h includes /usr/include/libintl.h, which chokes if dcgettext is defined as a macro. So include it now, to make later inclusions of a NOP. We don't include as well because people using "gettext.h" will not include , and also including would fail on SunOS 4, whereas is OK. */ #if defined(__sun) # include #endif /* Many header files from the libstdc++ coming with g++ 3.3 or newer include , which chokes if dcgettext is defined as a macro. So include it now, to make later inclusions of a NOP. */ #if defined(__cplusplus) && defined(__GNUG__) && (__GNUC__ >= 3) # include # if (__GLIBC__ >= 2) || _GLIBCXX_HAVE_LIBINTL_H # include # endif #endif /* Disabled NLS. The casts to 'const char *' serve the purpose of producing warnings for invalid uses of the value returned from these functions. On pre-ANSI systems without 'const', the config.h file is supposed to contain "#define const". */ # define gettext(Msgid) ((const char *) (Msgid)) # define dgettext(Domainname, Msgid) ((const char *) (Msgid)) # define dcgettext(Domainname, Msgid, Category) ((const char *) (Msgid)) # define ngettext(Msgid1, Msgid2, N) \ ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) # define dngettext(Domainname, Msgid1, Msgid2, N) \ ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) # define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \ ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) # define textdomain(Domainname) ((const char *) (Domainname)) # define bindtextdomain(Domainname, Dirname) ((const char *) (Dirname)) # define bind_textdomain_codeset(Domainname, Codeset) ((const char *) (Codeset)) #endif /* A pseudo function call that serves as a marker for the automated extraction of messages, but does not call gettext(). The run-time translation is done at a different place in the code. The argument, String, should be a literal string. Concatenated strings and other string expressions won't work. The macro's expansion is not parenthesized, so that it is suitable as initializer for static 'char[]' or 'const char[]' variables. */ #define gettext_noop(String) String /* The separator between msgctxt and msgid in a .mo file. */ #define GETTEXT_CONTEXT_GLUE "\004" /* Pseudo function calls, taking a MSGCTXT and a MSGID instead of just a MSGID. MSGCTXT and MSGID must be string literals. MSGCTXT should be short and rarely need to change. The letter 'p' stands for 'particular' or 'special'. */ #ifdef DEFAULT_TEXT_DOMAIN # define pgettext(Msgctxt, Msgid) \ pgettext_aux (DEFAULT_TEXT_DOMAIN, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES) #else # define pgettext(Msgctxt, Msgid) \ pgettext_aux (NULL, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES) #endif #define dpgettext(Domainname, Msgctxt, Msgid) \ pgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES) #define dcpgettext(Domainname, Msgctxt, Msgid, Category) \ pgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, Category) #ifdef DEFAULT_TEXT_DOMAIN # define npgettext(Msgctxt, Msgid, MsgidPlural, N) \ npgettext_aux (DEFAULT_TEXT_DOMAIN, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES) #else # define npgettext(Msgctxt, Msgid, MsgidPlural, N) \ npgettext_aux (NULL, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES) #endif #define dnpgettext(Domainname, Msgctxt, Msgid, MsgidPlural, N) \ npgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES) #define dcnpgettext(Domainname, Msgctxt, Msgid, MsgidPlural, N, Category) \ npgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, Category) #ifdef __GNUC__ __inline #else #ifdef __cplusplus inline #endif #endif static const char * pgettext_aux (const char *domain, const char *msg_ctxt_id, const char *msgid, int category) { const char *translation = dcgettext (domain, msg_ctxt_id, category); if (translation == msg_ctxt_id) return msgid; else return translation; } #ifdef __GNUC__ __inline #else #ifdef __cplusplus inline #endif #endif static const char * npgettext_aux (const char *domain, const char *msg_ctxt_id, const char *msgid, const char *msgid_plural, unsigned long int n, int category) { const char *translation = dcngettext (domain, msg_ctxt_id, msgid_plural, n, category); if (translation == msg_ctxt_id || translation == msgid_plural) return (n == 1 ? msgid : msgid_plural); else return translation; } /* The same thing extended for non-constant arguments. Here MSGCTXT and MSGID can be arbitrary expressions. But for string literals these macros are less efficient than those above. */ #include #define _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS \ (__GNUC__ >= 3 || __GNUG__ >= 2 /* || __STDC_VERSION__ >= 199901L */ ) #if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS #include #endif #define pgettext_expr(Msgctxt, Msgid) \ dcpgettext_expr (NULL, Msgctxt, Msgid, LC_MESSAGES) #define dpgettext_expr(Domainname, Msgctxt, Msgid) \ dcpgettext_expr (Domainname, Msgctxt, Msgid, LC_MESSAGES) #ifdef __GNUC__ __inline #else #ifdef __cplusplus inline #endif #endif static const char * dcpgettext_expr (const char *domain, const char *msgctxt, const char *msgid, int category) { size_t msgctxt_len = strlen (msgctxt) + 1; size_t msgid_len = strlen (msgid) + 1; const char *translation; #if _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS char msg_ctxt_id[msgctxt_len + msgid_len]; #else char buf[1024]; char *msg_ctxt_id = (msgctxt_len + msgid_len <= sizeof (buf) ? buf : (char *) malloc (msgctxt_len + msgid_len)); if (msg_ctxt_id != NULL) #endif { memcpy (msg_ctxt_id, msgctxt, msgctxt_len - 1); msg_ctxt_id[msgctxt_len - 1] = '\004'; memcpy (msg_ctxt_id + msgctxt_len, msgid, msgid_len); translation = dcgettext (domain, msg_ctxt_id, category); #if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS if (msg_ctxt_id != buf) free (msg_ctxt_id); #endif if (translation != msg_ctxt_id) return translation; } return msgid; } #define npgettext_expr(Msgctxt, Msgid, MsgidPlural, N) \ dcnpgettext_expr (NULL, Msgctxt, Msgid, MsgidPlural, N, LC_MESSAGES) #define dnpgettext_expr(Domainname, Msgctxt, Msgid, MsgidPlural, N) \ dcnpgettext_expr (Domainname, Msgctxt, Msgid, MsgidPlural, N, LC_MESSAGES) #ifdef __GNUC__ __inline #else #ifdef __cplusplus inline #endif #endif static const char * dcnpgettext_expr (const char *domain, const char *msgctxt, const char *msgid, const char *msgid_plural, unsigned long int n, int category) { size_t msgctxt_len = strlen (msgctxt) + 1; size_t msgid_len = strlen (msgid) + 1; const char *translation; #if _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS char msg_ctxt_id[msgctxt_len + msgid_len]; #else char buf[1024]; char *msg_ctxt_id = (msgctxt_len + msgid_len <= sizeof (buf) ? buf : (char *) malloc (msgctxt_len + msgid_len)); if (msg_ctxt_id != NULL) #endif { memcpy (msg_ctxt_id, msgctxt, msgctxt_len - 1); msg_ctxt_id[msgctxt_len - 1] = '\004'; memcpy (msg_ctxt_id + msgctxt_len, msgid, msgid_len); translation = dcngettext (domain, msg_ctxt_id, msgid_plural, n, category); #if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS if (msg_ctxt_id != buf) free (msg_ctxt_id); #endif if (!(translation == msg_ctxt_id || translation == msgid_plural)) return translation; } return (n == 1 ? msgid : msgid_plural); } #endif /* _LIBGETTEXT_H */ partclone-0.2.86/src/hfsplusclone.c000066400000000000000000000200151262102574200172350ustar00rootroot00000000000000/** hfsplusclone.c - part of Partclone project * * Copyright (c) 2007~ Thomas Tsai * * read hfsplus super block and bitmap * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "partclone.h" #include "hfsplusclone.h" #include "progress.h" #include "fs_common.h" struct HFSPlusVolumeHeader sb; int ret; char *EXECNAME = "partclone.hfsp"; extern fs_cmd_opt fs_opt; static short reverseShort(short s){ unsigned char c1, c2; c1 = s & 255; c2 = (s >> 8) & 255; return (c1 << 8)+c2; } static int reverseInt(int i){ unsigned char c1, c2, c3, c4; c1 = i & 255; c2 = (i >> 8) & 255; c3 = (i >> 16)& 255; c4 = (i >> 24)& 255; return ((int)c1<<24)+((int)c2<<16)+((int)c3<<8)+c4; } static int IsAllocationBlockUsed(UInt32 thisAllocationBlock, UInt8* allocationFileContents) { UInt8 thisByte; thisByte = allocationFileContents[thisAllocationBlock / 8]; //log_mesg(0, 0, 0, fs_opt.debug, "IsAB:%i\n", (thisByte & (1 << (7 - (thisAllocationBlock % 8))))); return (thisByte & (1 << (7 - (thisAllocationBlock % 8)))) != 0; } static void print_fork_data(HFSPlusForkData* fork){ int i = 0; HFSPlusExtentDescriptor* exten; log_mesg(2, 0, 0, fs_opt.debug, "%s: logicalSize: %#lx\n", __FILE__, fork->logicalSize); log_mesg(2, 0, 0, fs_opt.debug, "%s: clumpSize: %i\n", __FILE__, reverseInt(fork->clumpSize)); log_mesg(2, 0, 0, fs_opt.debug, "%s: totalBlocks: %i\n", __FILE__, reverseInt(fork->totalBlocks)); for (i = 0; i < 8; i++ ){ exten = &fork->extents[i]; log_mesg(2, 0, 0, fs_opt.debug, "%s: \texten %i startBlock: %i\n", __FILE__, i, reverseInt(exten->startBlock)); log_mesg(2, 0, 0, fs_opt.debug, "%s: \texten %i blockCount: %i\n", __FILE__, i, reverseInt(fork->extents[i].blockCount)); } } /// open device static void fs_open(char* device){ char *buffer; short HFS_Version; char HFS_Signature[2]; int HFS_Clean = 0; ret = open(device, O_RDONLY); if(lseek(ret, 1024, SEEK_SET) != 1024) log_mesg(0, 1, 1, fs_opt.debug, "%s: device %s seek fail\n", __FILE__, device); buffer = (char*)malloc(sizeof(HFSPlusVolumeHeader)); if (read (ret, buffer, sizeof(HFSPlusVolumeHeader)) != sizeof(HFSPlusVolumeHeader)) log_mesg(0, 1, 1, fs_opt.debug, "%s: read HFSPlusVolumeHeader fail\n", __FILE__); memcpy(&sb, buffer, sizeof(HFSPlusVolumeHeader)); HFS_Signature[0] = (char)sb.signature; HFS_Signature[1] = (char)(sb.signature>>8); HFS_Version = (short)reverseShort(sb.version); HFS_Clean = (reverseInt(sb.attributes)>>8) & 1; log_mesg(3, 0, 0, fs_opt.debug, "%s: Signature=%c%c\n", __FILE__, HFS_Signature[0], HFS_Signature[1]); log_mesg(3, 0, 0, fs_opt.debug, "%s: Version=%i\n", __FILE__, HFS_Version); log_mesg(3, 0, 0, fs_opt.debug, "%s: Attr-Unmounted=%i(1 is clean, 0 is dirty)\n", __FILE__, HFS_Clean); log_mesg(3, 0, 0, fs_opt.debug, "%s: Attr-Inconsistent=%i\n", __FILE__, (reverseInt(sb.attributes)>>11) & 1); if(fs_opt.ignore_fschk){ log_mesg(1, 0, 0, fs_opt.debug, "%s: Ignore filesystem check\n", __FILE__); } else { if (HFS_Clean) log_mesg(3, 0, 0, fs_opt.debug, "%s: HFS_Plus '%s' is clean\n", __FILE__, device); else log_mesg(0, 1, 1, fs_opt.debug, "%s: HFS_Plus Volume '%s' is scheduled for a check or it was shutdown\nuncleanly. Please fix it by fsck.\n", __FILE__, device); } free(buffer); } static void fs_close(){ close(ret); } extern void readbitmap(char* device, image_head image_hdr, unsigned long* bitmap, int pui){ int IsUsed = 0; UInt8 *extent_bitmap; UInt32 bused = 0, bfree = 0, mused = 0; UInt32 block = 0, extent_block = 0, tb = 0; int allocation_exten = 0; UInt32 allocation_start_block; UInt32 allocation_block_size; int start = 0; int bit_size = 1; fs_open(device); tb = reverseInt(sb.totalBlocks); /// init progress progress_bar prog; /// progress_bar structure defined in progress.h progress_init(&prog, start, image_hdr.totalblock, image_hdr.totalblock, BITMAP, bit_size); memset(bitmap, 0xFF, sizeof(unsigned long)*LONGS(tb)); for (allocation_exten = 0; allocation_exten <= 7; allocation_exten++){ allocation_start_block = 4096*reverseInt(sb.allocationFile.extents[allocation_exten].startBlock); allocation_block_size = 4096*reverseInt(sb.allocationFile.extents[allocation_exten].blockCount); log_mesg(2, 0, 0, 2, "%s: tb = %lu\n", __FILE__, tb); log_mesg(2, 0, 0, 2, "%s: extent_block = %lu\n", __FILE__, extent_block); log_mesg(2, 0, 0, 2, "%s: allocation_exten = %i\n", __FILE__, allocation_exten); log_mesg(2, 0, 0, 2, "%s: allocation_start_block = %lu\n", __FILE__, allocation_start_block); log_mesg(2, 0, 0, 2, "%s: allocation_block_size = %lu\n", __FILE__, allocation_block_size); if((allocation_start_block == 0) && (allocation_block_size == 0)){ continue; } if(lseek(ret, allocation_start_block, SEEK_SET) != allocation_start_block) log_mesg(0, 1, 1, fs_opt.debug, "%s: start_block %i seek fail\n", __FILE__, allocation_start_block); extent_bitmap = (UInt8*)malloc(allocation_block_size); if(read(ret, extent_bitmap, allocation_block_size) != allocation_block_size) log_mesg(0, 0, 1, fs_opt.debug, "%s: read hfsp bitmap fail\n", __FILE__); for(extent_block = 0 ; (extent_block < allocation_block_size*8) && (block< tb); extent_block++){ IsUsed = IsAllocationBlockUsed(extent_block, extent_bitmap); if (IsUsed){ bused++; pc_set_bit(block, bitmap); log_mesg(3, 0, 0, fs_opt.debug, "%s: used block= %i\n", __FILE__, block); } else { bfree++; pc_clear_bit(block, bitmap); log_mesg(3, 0, 0, fs_opt.debug, "%s: free block= %i\n", __FILE__, block); } block++; /// update progress update_pui(&prog, block, block, 0); } free(extent_bitmap); log_mesg(2, 0, 0, 2, "%s: next exten\n", __FILE__); log_mesg(2, 0, 0, 2, "%s: extent_bitmap:%i\n", __FILE__, extent_bitmap); log_mesg(2, 0, 0, 2, "%s: bfree:%i\n", __FILE__, bfree); log_mesg(2, 0, 0, 2, "%s: bused:%i\n", __FILE__, bused); } mused = (reverseInt(sb.totalBlocks) - reverseInt(sb.freeBlocks)); if(bused != mused) log_mesg(0, 1, 1, fs_opt.debug, "%s: bitmap count error, used:%lu, mbitmap:%lu\n", __FILE__, bused, mused); fs_close(); /// update progress update_pui(&prog, 1, 1, 1); } extern void initial_image_hdr(char* device, image_head* image_hdr) { fs_open(device); strncpy(image_hdr->magic, IMAGE_MAGIC, IMAGE_MAGIC_SIZE); strncpy(image_hdr->fs, hfsplus_MAGIC, FS_MAGIC_SIZE); image_hdr->block_size = (int)reverseInt(sb.blockSize); image_hdr->totalblock = (unsigned long long)reverseInt(sb.totalBlocks); image_hdr->device_size = (unsigned long long)(image_hdr->block_size * image_hdr->totalblock); image_hdr->usedblocks = (unsigned long long)(reverseInt(sb.totalBlocks) - reverseInt(sb.freeBlocks)); log_mesg(2, 0, 0, 2, "%s: blockSize:%i\n", __FILE__, reverseInt(sb.blockSize)); log_mesg(2, 0, 0, 2, "%s: totalBlocks:%i\n", __FILE__, reverseInt(sb.totalBlocks)); log_mesg(2, 0, 0, 2, "%s: freeBlocks:%i\n", __FILE__, reverseInt(sb.freeBlocks)); print_fork_data(&sb.allocationFile); print_fork_data(&sb.extentsFile); print_fork_data(&sb.catalogFile); print_fork_data(&sb.attributesFile); print_fork_data(&sb.startupFile); fs_close(); } partclone-0.2.86/src/hfsplusclone.h000066400000000000000000000044751262102574200172560ustar00rootroot00000000000000/** * hfsplusclone.h - part of Partclone project * * Copyright (c) 2007~ Thomas Tsai * * read hfsplus super block and bitmap * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ typedef uint8_t UInt8; typedef uint16_t UInt16; typedef uint32_t UInt32; typedef uint64_t UInt64; typedef UInt32 HFSCatalogNodeID; struct HFSPlusExtentDescriptor { UInt32 startBlock; UInt32 blockCount; }; typedef struct HFSPlusExtentDescriptor HFSPlusExtentDescriptor; //typedef struct HFSPlusExtentDescriptor HFSPlusExtentRecord; struct HFSPlusForkData { UInt64 logicalSize; UInt32 clumpSize; UInt32 totalBlocks; HFSPlusExtentDescriptor extents[8]; }; typedef struct HFSPlusForkData HFSPlusForkData; struct HFSPlusVolumeHeader { UInt16 signature; UInt16 version; UInt32 attributes; UInt32 lastMountedVersion; UInt32 journalInfoBlock; UInt32 createDate; UInt32 modifyDate; UInt32 backupDate; UInt32 checkedDate; UInt32 fileCount; UInt32 folderCount; UInt32 blockSize; UInt32 totalBlocks; UInt32 freeBlocks; UInt32 nextAllocation; UInt32 rsrcClumpSize; UInt32 dataClumpSize; HFSCatalogNodeID nextCatalogID; UInt32 writeCount; UInt64 encodingsBitmap; UInt32 finderInfo[8]; HFSPlusForkData allocationFile; HFSPlusForkData extentsFile; HFSPlusForkData catalogFile; HFSPlusForkData attributesFile; HFSPlusForkData startupFile; }; typedef struct HFSPlusVolumeHeader HFSPlusVolumeHeader; /// read super block and write to image head extern void initial_image_hdr(char* device, image_head* image_hdr); /// readbitmap - cread and heck bitmap, reference dumpe2fs extern void readbitmap(char* device, image_head image_hdr, unsigned long* bitmap, int pui); partclone-0.2.86/src/info.c000066400000000000000000000111111262102574200154600ustar00rootroot00000000000000/** * The part of partclone * * Copyright (c) 2007~ Thomas Tsai * * The utility to print out the Image information. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ #include #include #include #include #include #include #include #include #include #include #include #include /** * partclone.h - include some structures like image_head, opt_cmd, .... * and functions for main used. */ #include "partclone.h" /// cmd_opt structure defined in partclone.h cmd_opt opt; void info_usage(void) { fprintf(stderr, "partclone v%s http://partclone.org\n" "Usage: partclone.info [FILE]\n" "Or: partclone.info [OPTIONS]\n" "\n" " -s, --source FILE Source FILE, or stdin(-)\n" " -L, --logfile FILE Log FILE\n" " -dX, --debug=X Set the debug level to X = [0|1|2]\n" " -q, --quiet Disable progress message\n" " -v, --version Display partclone version\n" " -h, --help Display this help\n" , VERSION); exit(1); } void info_options (int argc, char **argv){ static const char *sopt = "-hvqd::L:s:"; static const struct option lopt[] = { { "help", no_argument, NULL, 'h' }, { "print_version", no_argument, NULL, 'v' }, { "source", required_argument, NULL, 's' }, { "debug", optional_argument, NULL, 'd' }, { "logfile", required_argument, NULL, 'L' }, { "quiet", no_argument, NULL, 'q' }, { NULL, 0, NULL, 0 } }; int c; memset(&opt, 0, sizeof(cmd_opt)); opt.debug = 0; opt.quiet = 0; opt.logfile = "/var/log/partclone.log"; opt.target = 0; opt.clone = 0; opt.restore = 0; opt.info = 1; while ((c = getopt_long(argc, argv, sopt, lopt, NULL)) != -1) { switch (c) { case 'h': case '?': info_usage(); break; case 'v': print_version(); break; case 's': opt.source = optarg; break; case 'q': opt.quiet = 1; break; case 'd': if (optarg) opt.debug = atol(optarg); else opt.debug = 1; break; case 'L': opt.logfile = optarg; break; default: fprintf(stderr, "Unknown option '%s'.\n", argv[optind-1]); info_usage(); } } if ( opt.source == 0 ) info_usage(); } /** * main functiom - print Image file metadata. */ int main(int argc, char **argv){ int dfr; /// file descriptor for source and target unsigned long *bitmap; /// the point for bitmap data image_head image_hdr; /// image_head structure defined in partclone.h if (argc == 2){ memset(&opt, 0, sizeof(cmd_opt)); opt.source = argv[1]; opt.logfile = "/var/log/partclone.log"; dfr = open(opt.source, O_RDONLY); if (dfr == -1) info_options(argc, argv); } else info_options(argc, argv); open_log(opt.logfile); /// print partclone info print_partclone_info(opt); /** * open Image file */ if (strcmp(opt.source, "-") == 0) { if ((dfr = fileno(stdin)) == -1) log_mesg(0, 1, 1, opt.debug, "info: open %s(stdin) error\n", opt.source); } else { dfr = open(opt.source, O_RDONLY); if (dfr == -1) log_mesg(0, 1, 1, opt.debug, "info: Can't open file(%s)\n", opt.source); } /// get image information from image file restore_image_hdr(&dfr, &opt, &image_hdr); if (memcmp(image_hdr.magic, IMAGE_MAGIC, IMAGE_MAGIC_SIZE) != 0) log_mesg(0, 1, 1, opt.debug, "The Image magic error. This file is NOT partclone Image\n"); /// alloc a memory to restore bitmap bitmap = (unsigned long*)calloc(sizeof(unsigned long), LONGS(image_hdr.totalblock)); if (bitmap == NULL) log_mesg(0, 1, 1, opt.debug, "%s, %i, not enough memory\n", __func__, __LINE__); log_mesg(0, 0, 0, opt.debug, "initial main bitmap pointer %p\n", bitmap); log_mesg(0, 0, 0, opt.debug, "Initial image hdr: read bitmap table\n"); /// read and check bitmap from image file get_image_bitmap(&dfr, opt, image_hdr, bitmap); log_mesg(0, 0, 0, opt.debug, "check main bitmap pointer %p\n", bitmap); log_mesg(0, 0, 0, opt.debug, "print image_head\n"); /// print image_head print_image_hdr_info(image_hdr, opt); close(dfr); /// close source free(bitmap); /// free bitmp close_log(); return 0; /// finish } partclone-0.2.86/src/jfsclone.c000066400000000000000000000374051262102574200163460ustar00rootroot00000000000000/** * jfsclone.c - part of Partclone project * * Copyright (c) 2007~ Thomas Tsai * * read reiserfs super block and bitmap * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "partclone.h" #include "jfsclone.h" #include "progress.h" #include "fs_common.h" /* DMAP BLOCK TYPES */ #define DMAP -1 #define LEVEL0 0 #define LEVEL1 1 #define LEVEL2 2 /* DMAP BLOCK CALCULATIONS */ #define L0FACTOR (LPERCTL + 1) //LPERCTL=1024 #define L1FACTOR ((L0FACTOR * LPERCTL) + 1) #define L1PAGE(l1) (2 + ((l1) * L1FACTOR)) #define L0PAGE(l1, l0) (L1PAGE(l1) + 1 + ((l0) * L0FACTOR)) #define DMAPPAGE(l1, l0, d) (L0PAGE(l1, l0) + 1 + (d)) #define XT_CMP(CMP, K, X) \ { \ int64_t offset64 = offsetXAD(X); \ (CMP) = ((K) >= offset64 + lengthXAD(X)) ? 1 : \ ((K) < offset64) ? -1 : 0 ; \ } int ujfs_rwdaddr(FILE *, int64_t *, struct dinode *, int64_t, int32_t, int32_t); static int decode_pagenum(int64_t page, int *l1, int *l0, int *dmap); static int find_iag(unsigned iagnum, unsigned which_table, int64_t * address); static int find_inode(unsigned inum, unsigned which_table, int64_t * address); static int xRead(int64_t, unsigned, char *); static int jfs_bit_inuse(unsigned *bitmap, uint64_t block); static void get_all_used_blocks(uint64_t *total_blocks, uint64_t *used_blocks); struct superblock sb; FILE *fp; int bsize; short l2bsize; unsigned jfs_type; char *EXECNAME = "partclone.jfs"; extern fs_cmd_opt fs_opt; /// libfs/jfs_endian.h #define GET 0 /// libfs/devices.h /// xpeek.h #define AGGREGATE_2ND_I -1 /// open device static void fs_open(char* device){ fp = fopen(device, "r+"); if (fp == NULL) { log_mesg(0, 1, 1, fs_opt.debug, "%s: Cannot open device %s.\n", __FILE__, device); } if (ujfs_get_superblk(fp, &sb, 1)) { log_mesg(0, 1, 1, fs_opt.debug, "%s: error reading primary superblock\n", __FILE__); if (ujfs_get_superblk(fp, &sb, 0)) { log_mesg(0, 1, 1, fs_opt.debug, "%s: error reading secondary superblock\n", __FILE__); } else log_mesg(1, 0, 0, fs_opt.debug, "%s: using secondary superblock\n", __FILE__); } jfs_type = sb.s_flag; l2bsize = sb.s_l2bsize; bsize = sb.s_bsize; log_mesg(1, 0, 0, fs_opt.debug, "%s: type = %u\n", __FILE__, sb.s_flag); log_mesg(1, 0, 0, fs_opt.debug, "%s: block size = %i\n", __FILE__, sb.s_bsize); log_mesg(1, 0, 0, fs_opt.debug, "%s: magic = %s\n", __FILE__, sb.s_magic); log_mesg(1, 0, 0, fs_opt.debug, "%s: version = %u\n", __FILE__, sb.s_version); log_mesg(1, 0, 0, fs_opt.debug, "%s: blocks = %lli\n", __FILE__, sb.s_size); log_mesg(1, 0, 0, fs_opt.debug, "%s: l2bsize = %i\n", __FILE__, sb.s_l2bsize); } /// close device static void fs_close(){ fclose(fp); } /// readbitmap - read bitmap extern void readbitmap(char* device, image_head image_hdr, unsigned long* bitmap, int pui){ int64_t lblock = 0; int64_t address; int64_t cntl_addr; int ret = 1; struct dinode bmap_inode; struct dbmap cntl_page; int dmap_l2bpp; int64_t d_address; struct dmap d_map; int dmap_i, l0, l1; int next = 1; uint64_t tub=0; int64_t tb=0; int64_t pb = 1; int64_t block_used = 0; int64_t block_free = 0; uint64_t logloc = 0; int logsize = 0; int64_t dn_mapsize = 0; int start = 0; int bit_size = 1; fs_open(device); /// Read Blocal Allocation Map Inode ret = find_inode(BMAP_I, AGGREGATE_I, &address); if (ret){ log_mesg(0, 1, 1, fs_opt.debug, "%s(%i):find_node error.\n", __FILE__, __LINE__); } ret = xRead(address, sizeof(struct dinode), (char *) &bmap_inode); if (ret){ log_mesg(0, 1, 1, fs_opt.debug, "%s(%i):xRead error.\n", __FILE__, __LINE__); } /// Read overall control page for the map ret = ujfs_rwdaddr(fp, &cntl_addr, &bmap_inode, (int64_t) 0, GET, bsize); if (ret){ log_mesg(0, 1, 1, fs_opt.debug, "%s(%i):ujfs_rwdaddr error.\n", __FILE__, __LINE__); } ret = xRead(cntl_addr, sizeof(struct dbmap), (char *) &cntl_page); if (ret){ log_mesg(0, 1, 1, fs_opt.debug, "%s(%i):xRead error %i\n", __FILE__, __LINE__); } dn_mapsize = cntl_page.dn_mapsize; dmap_l2bpp = cntl_page.dn_l2nbperpage; /// display leaf lblock = 0; //control page decode_pagenum(lblock, &l1, &l0, &dmap_i); ret = ujfs_rwdaddr(fp, &d_address, &bmap_inode, (lblock) << dmap_l2bpp, GET, bsize); if (ret){ log_mesg(0, 1, 1, fs_opt.debug, "%s(%i):ujfs_rwdaddr error.\n", __FILE__, __LINE__); } ret = xRead(d_address, sizeof(struct dmap), (char *)&d_map); if (ret){ log_mesg(0, 1, 1, fs_opt.debug, "%s(%i):xRead error.\n", __FILE__, __LINE__); } /// ujfs_swap_dmap(&d_map); fixme log_mesg(2, 0, 0, fs_opt.debug, "%s: Dmap page at block %lld\n", __FILE__, (long long) (d_address >> sb.s_l2bsize)); log_mesg(2, 0, 0, fs_opt.debug, "%s: control nblocks %d\n", __FILE__, d_map.nblocks); log_mesg(2, 0, 0, fs_opt.debug, "%s: control nfree %d\n", __FILE__, d_map.nfree); lblock = 4; //First map page logloc = addressPXD(&(sb.s_logpxd)); logsize = lengthPXD(&(sb.s_logpxd)); log_mesg(1, 0, 0, fs_opt.debug, "%s: logloc %lli, logsize %i\n", __FILE__, logloc, logsize); /// init progress progress_bar prog; /// progress_bar structure defined in progress.h progress_init(&prog, start, image_hdr.totalblock, image_hdr.totalblock, BITMAP, bit_size); memset(bitmap, 0xFF, sizeof(unsigned long)*LONGS(image_hdr.totalblock)); while(next){ block_used = 0; block_free = 0; log_mesg(2, 0, 0, fs_opt.debug, "%s:lblock = %lli\n", __FILE__, lblock); decode_pagenum(lblock, &l1, &l0, &dmap_i); ret = ujfs_rwdaddr(fp, &d_address, &bmap_inode, (lblock) << dmap_l2bpp, GET, bsize); if (ret){ //log_mesg(0, 1, 1, fs_opt.debug, "%s(%i):ujfs_rwdaddr error(%s).\n", __FILE__, __LINE__, strerror(ret)); log_mesg(2, 0, 0, fs_opt.debug, "%s(%i):ujfs_rwdaddr error(%s).\n", __FILE__, __LINE__, strerror(ret)); } ret = xRead(d_address, sizeof(struct dmap), (char *)&d_map); if (ret){ log_mesg(0, 1, 1, fs_opt.debug, "%s(%i):xRead error.\n", __FILE__, __LINE__); } ///ujfs_swap_dmap(&d_map); log_mesg(2, 0, 0, fs_opt.debug, "%s: Dmap page at block %lld\n", __FILE__, (long long) (d_address >> sb.s_l2bsize)); log_mesg(2, 0, 0, fs_opt.debug, "%s: nblocks %d\n", __FILE__, d_map.nblocks); log_mesg(2, 0, 0, fs_opt.debug, "%s: nfree %d\n", __FILE__, d_map.nfree); /// bitmap information not cover all partition /// display bitmap block_used = 0; for (pb = 0; (pb < d_map.nblocks) && (tb < dn_mapsize); pb++){ if (tb > dn_mapsize) break; if (jfs_bit_inuse(d_map.wmap, pb) == 1){ block_used++; log_mesg(3, 0, 0, fs_opt.debug, "%s: used pb = %lli tb = %lli\n", __FILE__, pb, tb); pc_set_bit(tb, bitmap); } else { block_free++; log_mesg(3, 0, 0, fs_opt.debug, "%s: free pb = %lli tb = %lli\n", __FILE__, pb, tb); pc_clear_bit(tb, bitmap); } tb++; update_pui(&prog, tb, tb, 0);//keep update } log_mesg(2, 0, 0, fs_opt.debug, "%s:block_used %lli block_free %lli\n", __FILE__, block_used, block_free); tub += block_used; next = 0; if (((lblock-4)*d_map.nblocks)= dn_mapsize) next = 0; } log_mesg(2, 0, 0, fs_opt.debug, "%s:data_used = %llu\n", __FILE__, tub); block_used = 0; /// log log_mesg(2, 0, 0, fs_opt.debug, "%s:%llu log %llu\n", __FILE__, logloc, (logloc+logsize)); for (;tb <= image_hdr.totalblock; tb++){ if ((tb >= logloc) && (tb < (logloc+logsize))){ pc_set_bit(tb, bitmap); block_used++; log_mesg(3, 0, 0, fs_opt.debug, "%s: log used tb = %llu\n", __FILE__, pb, tb); } update_pui(&prog, tb, tb, 0);//keep update } log_mesg(2, 0, 0, fs_opt.debug, "%s:log_used = %llu\n", __FILE__, block_used); log_mesg(1, 0, 0, fs_opt.debug, "%s:total_used = %llu\n", __FILE__, tub+block_used); fs_close(); update_pui(&prog, 1, 1, 1);//finish } /// read super block and write to image head extern void initial_image_hdr(char* device, image_head* image_hdr){ uint64_t used_blocks = 0; uint64_t total_blocks = 0; fs_open(device); get_all_used_blocks(&total_blocks, &used_blocks); strncpy(image_hdr->magic, IMAGE_MAGIC, IMAGE_MAGIC_SIZE); strncpy(image_hdr->fs, jfs_MAGIC, FS_MAGIC_SIZE); image_hdr->block_size = (int)sb.s_bsize; image_hdr->totalblock = (unsigned long long)total_blocks; image_hdr->usedblocks = (unsigned long long)used_blocks; image_hdr->device_size =(unsigned long long)(total_blocks * sb.s_bsize); fs_close(); } /// get_all_used_blocks extern void get_all_used_blocks(uint64_t *total_blocks, uint64_t *used_blocks){ int64_t address; int64_t cntl_addr; int ret = 1; struct dinode bmap_inode; struct dbmap cntl_page; int64_t bytes_on_device = 0; int logsize = 0; /// Read Blocal Allocation Map Inode ret = find_inode(BMAP_I, AGGREGATE_I, &address); if (ret){ log_mesg(0, 1, 1, fs_opt.debug, "%s(%i):find_node error.\n", __FILE__, __LINE__); } ret = xRead(address, sizeof(struct dinode), (char *) &bmap_inode); if (ret){ log_mesg(0, 1, 1, fs_opt.debug, "%s(%i):xRead error.\n", __FILE__, __LINE__); } /// Read overall control page for the map ret = ujfs_rwdaddr(fp, &cntl_addr, &bmap_inode, (int64_t) 0, GET, bsize); if (ret){ log_mesg(0, 1, 1, fs_opt.debug, "%s(%i):ujfs_rwdaddr error.\n", __FILE__, __LINE__); } ret = xRead(cntl_addr, sizeof(struct dbmap), (char *) &cntl_page); if (ret){ log_mesg(0, 1, 1, fs_opt.debug, "%s(%i):xRead error.\n", __FILE__, __LINE__); } logsize = lengthPXD(&(sb.s_logpxd)); ret = ujfs_get_dev_size(fp, &bytes_on_device); *total_blocks = bytes_on_device / sb.s_bsize; *used_blocks = (cntl_page.dn_mapsize - cntl_page.dn_nfree + logsize); log_mesg(2, 0, 0, fs_opt.debug, "%s: dn.mapsize = %lli\n", __FILE__, cntl_page.dn_mapsize); log_mesg(2, 0, 0, fs_opt.debug, "%s: total_blocks = %lli\n", __FILE__, *total_blocks); log_mesg(2, 0, 0, fs_opt.debug, "%s: free_blocks = %lli\n", __FILE__, cntl_page.dn_nfree); log_mesg(2, 0, 0, fs_opt.debug, "%s: log_blocks = %i\n", __FILE__, logsize); } int decode_pagenum(int64_t page, int *l1, int *l0, int *dmap) { int remainder; if (page == 0) return -1; if (page == 1) return LEVEL2; *l1 = (page - 2) / L1FACTOR; remainder = (page - 2) % L1FACTOR; if (remainder == 0) return LEVEL1; *l0 = (remainder - 1) / L0FACTOR; remainder = (remainder - 1) % L0FACTOR; if (remainder == 0) return LEVEL0; *dmap = remainder - 1; return DMAP; } int find_inode(unsigned inum, unsigned which_table, int64_t * address) { int extnum; struct iag iag; int iagnum; int64_t map_address; int rc; iagnum = INOTOIAG(inum); extnum = (inum & (INOSPERIAG - 1)) >> L2INOSPEREXT; if (find_iag(iagnum, which_table, &map_address) == 1) return 1; rc = ujfs_rw_diskblocks(fp, map_address, sizeof (struct iag), &iag, GET); if (rc) { log_mesg(1, 1, 1, fs_opt.debug, "%s: find_inode: Error reading iag\n", __FILE__); return 1; } /* swap if on big endian machine */ ///ujfs_swap_iag(&iag); if (iag.inoext[extnum].len == 0) return 1; *address = (addressPXD(&iag.inoext[extnum]) << l2bsize) + ((inum & (INOSPEREXT - 1)) * sizeof (struct dinode)); return 0; } int xRead(int64_t address, unsigned count, char *buffer) { int64_t block_address; char *block_buffer; int64_t length; unsigned offset; offset = address & (bsize - 1); length = (offset + count + bsize - 1) & ~(bsize - 1); log_mesg(3, 0, 0, fs_opt.debug, "%s: offset %i, length %lli, count %i, address %lli\n", __FILE__, offset , length , count , address); if ((offset == 0) & (length == count)) return ujfs_rw_diskblocks(fp, address, count, buffer, GET); block_address = address - offset; block_buffer = (char *) malloc(length); if (block_buffer == 0) return 1; if (ujfs_rw_diskblocks(fp, block_address, length, block_buffer, GET)) { log_mesg(3, 0, 0, fs_opt.debug, "%s: block_address %lli , length %lli , GET %i \n", __FILE__, block_address, length, GET); free(block_buffer); return 1; } memcpy(buffer, block_buffer + offset, count); free(block_buffer); log_mesg(3, 0, 0, fs_opt.debug, "%s: done: offset %i, length %lli, count %i, address %lli\n", __FILE__, offset , length , count , address); return 0; } int find_iag(unsigned iagnum, unsigned which_table, int64_t * address) { int base; char buffer[PSIZE]; int cmp; struct dinode fileset_inode; int64_t fileset_inode_address; int64_t iagblock; int index; int lim; xtpage_t *page; int rc; int64_t AIT_2nd_offset = addressPXD(&(sb.s_ait2)) * sb.s_bsize; if (which_table != FILESYSTEM_I && which_table != AGGREGATE_I && which_table != AGGREGATE_2ND_I) { log_mesg(1, 1, 1, fs_opt.debug, "%s: find_iag: Invalid fileset, %d\n", __FILE__, which_table); return 1; } iagblock = IAGTOLBLK(iagnum, L2PSIZE - l2bsize); if (which_table == AGGREGATE_2ND_I) { fileset_inode_address = AIT_2nd_offset + sizeof (struct dinode); } else { fileset_inode_address = AGGR_INODE_TABLE_START + (which_table * sizeof (struct dinode)); } rc = xRead(fileset_inode_address, sizeof (struct dinode), (char *) &fileset_inode); if (rc) { log_mesg(1, 1, 1, fs_opt.debug, "%s: find_inode: Error reading fileset inode\n", __FILE__); return 1; } page = (xtpage_t *) & (fileset_inode.di_btroot); descend: /* Binary search */ for (base = XTENTRYSTART, lim = __le16_to_cpu(page->header.nextindex) - XTENTRYSTART; lim; lim >>= 1) { index = base + (lim >> 1); XT_CMP(cmp, iagblock, &(page->xad[index])); if (cmp == 0) { /* HIT! */ if (page->header.flag & BT_LEAF) { *address = (addressXAD(&(page->xad[index])) + (iagblock - offsetXAD(&(page->xad[index])))) << l2bsize; return 0; } else { rc = xRead(addressXAD(&(page->xad[index])) << l2bsize, PSIZE, buffer); if (rc) { log_mesg(1, 1, 1, fs_opt.debug, "%s: find_iag: Error reading btree node\n", __FILE__); return 1; } page = (xtpage_t *) buffer; goto descend; } } else if (cmp > 0) { base = index + 1; --lim; } } if (page->header.flag & BT_INTERNAL) { /* Traverse internal page, it might hit down there * If base is non-zero, decrement base by one to get the parent * entry of the child page to search. */ index = base ? base - 1 : base; rc = xRead(addressXAD(&(page->xad[index])) << l2bsize, PSIZE, buffer); if (rc) { log_mesg(1, 1, 1, fs_opt.debug, "%s: find_iag: Error reading btree node\n", __FILE__); return 1; } page = (xtpage_t *) buffer; goto descend; } /* Not found! */ log_mesg(1, 1, 1, fs_opt.debug, "%s: find_iag: IAG %d not found!\n", __FILE__, iagnum); return 1; } int jfs_bit_inuse(unsigned *bitmap, uint64_t block){ uint64_t byte = 0; int bit = 0; byte = block/32; bit = 31 - (block%32); log_mesg(3, 0, 0, fs_opt.debug, "%s: bitmap = %08x\n", __FILE__, bitmap[byte]); if(bitmap[byte] & (1< * * read reiser4 super block and bitmap * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ /// readbitmap - read bitmap extern void readbitmap(char* device, image_head image_hdr, unsigned long* bitmap, int pui); /// read super block and write to image head extern void initial_image_hdr(char* device, image_head* image_hdr); partclone-0.2.86/src/main.c000066400000000000000000000737441262102574200154750ustar00rootroot00000000000000/** * The main program of partclone * * Copyright (c) 2007~ Thomas Tsai * * clone/restore partition to a image, device or stdout. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /** * progress.h - only for progress bar */ #include "progress.h" void *thread_update_pui(void *arg); /// progress_bar structure defined in progress.h progress_bar prog; unsigned long long copied; unsigned long long block_id; int done; /** * partclone.h - include some structures like image_head, opt_cmd, .... * and functions for main used. */ #include "partclone.h" /// cmd_opt structure defined in partclone.h cmd_opt opt; /** * Include different filesystem header depend on what flag you want. * If cflag is _EXTFS, output to extfsclone. * My goal is give different clone utils by makefile . */ #ifdef EXTFS #include "extfsclone.h" #define FS "EXTFS" #elif REISERFS #include "reiserfsclone.h" #define FS "REISERFS" #elif REISER4 #include "reiser4clone.h" #define FS "REISER4" #elif XFS #include "xfsclone.h" #define FS "XFS" #elif HFSPLUS #include "hfsplusclone.h" #define FS "HFS Plus" #elif FAT #include "fatclone.h" #define FS "FAT" #elif NTFS #include "ntfsclone-ng.h" #define FS "NTFS" #elif NTFS3G #include "ntfsclone-ng.h" #define FS "NTFS" #elif UFS #include "ufsclone.h" #define FS "UFS" #elif VMFS #include "vmfsclone.h" #define FS "VMFS" #elif JFS #include "jfsclone.h" #define FS "JFS" #elif BTRFS #include "btrfsclone.h" #define FS "BTRFS" #elif EXFAT #include "exfatclone.h" #define FS "EXFAT" #elif F2FS #include "f2fsclone.h" #define FS "F2FS" #elif MINIX #include "minixclone.h" #define FS "MINIX" #elif NILFS #include "nilfsclone.h" #define FS "NILFS" #elif IMG #include "ddclone.h" #define FS "raw" char *EXECNAME = "partclone.imager"; #elif DD #include "ddclone.h" #define FS "raw" #ifdef RESTORE char *EXECNAME = "partclone.restore"; #else #ifdef CHKIMG char *EXECNAME = "partclone.chkimg"; #else char *EXECNAME = "partclone.dd"; #endif #endif #endif /// fs option #include "fs_common.h" /// cmd_opt structure defined in partclone.h fs_cmd_opt fs_opt; /** * main function - for clone or restore data */ int main(int argc, char **argv) { #ifdef MEMTRACE setenv("MALLOC_TRACE", "partclone_mtrace.log", 1); mtrace(); #endif char* source; /// source data char* target; /// target data int dfr, dfw; /// file descriptor for source and target int r_size, w_size; /// read and write size int start, stop; /// start, range, stop number for progress bar char bitmagic[8] = "BiTmAgIc";// only for check postition char bitmagic_r[8]="00000000";/// read magic string from image unsigned long *bitmap = NULL; /// the point for bitmap data int debug = 0; /// debug level int tui = 0; /// text user interface int pui = 0; /// progress mode(default text) int flag; int pres = 0; pthread_t prog_thread; void *p_result; static const char *const bad_sectors_warning_msg = "*************************************************************************\n" "* WARNING: The disk has bad sectors. This means physical damage on the *\n" "* disk surface caused by deterioration, manufacturing faults, or *\n" "* another reason. The reliability of the disk may remain stable or *\n" "* degrade quickly. Use the --rescue option to efficiently save as much *\n" "* data as possible! *\n" "*************************************************************************\n"; image_head image_hdr; /// image_head structure defined in partclone.h memset(&image_hdr, 0, sizeof(image_hdr)); /** * get option and assign to opt structure * check parameter and read from argv */ parse_options(argc, argv, &opt); /** * if "-d / --debug" given * open debug file in "/var/log/partclone.log" for log message */ memset(&fs_opt, 0, sizeof(fs_cmd_opt)); debug = opt.debug; fs_opt.debug = debug; fs_opt.ignore_fschk = opt.ignore_fschk; //if(opt.debug) open_log(opt.logfile); /** * using Text User Interface */ if (opt.ncurses) { pui = NCURSES; log_mesg(1, 0, 0, debug, "Using Ncurses User Interface mode.\n"); } else pui = TEXT; tui = open_pui(pui, opt.fresh); if ((opt.ncurses) && (!tui)) { opt.ncurses = 0; pui = TEXT; log_mesg(1, 0, 0, debug, "Open Ncurses User Interface Error.\n"); } /// print partclone info print_partclone_info(opt); #ifndef CHKIMG if (geteuid() != 0) log_mesg(0, 1, 1, debug, "You are not logged as root. You may have \"access denied\" errors when working.\n"); else log_mesg(1, 0, 0, debug, "UID is root.\n"); #endif /// ignore crc check if (opt.ignore_crc) log_mesg(1, 0, 1, debug, "Ignore CRC errors\n"); /** * open source and target * clone mode, source is device and target is image file/stdout * restore mode, source is image file/stdin and target is device * dd mode, source is device and target is device !!not complete */ source = opt.source; target = opt.target; log_mesg(1, 0, 0, debug, "source=%s, target=%s \n", source, target); dfr = open_source(source, &opt); if (dfr == -1) { log_mesg(0, 1, 1, debug, "Error exit\n"); } #ifndef CHKIMG dfw = open_target(target, &opt); if (dfw == -1) { log_mesg(0, 1, 1, debug, "Error exit\n"); } #else dfw = -1; #endif /** * get partition information like super block, image_head, bitmap * from device or image file. */ if (opt.clone) { char bbuffer[16384]; unsigned long long i; unsigned long long needed_mem = 0; unsigned long long needed_size = 0; log_mesg(1, 0, 0, debug, "Initial image hdr - get Super Block from partition\n"); log_mesg(0, 0, 1, debug, "Reading Super Block\n"); /// get Super Block information from partition initial_image_hdr(source, &image_hdr); /// check memory size if (check_mem_size(image_hdr, opt, &needed_mem) == -1) log_mesg(0, 1, 1, debug, "There is not enough free memory, partclone suggests you should have %llu bytes memory\n", needed_mem); strncpy(image_hdr.version, IMAGE_VERSION, VERSION_SIZE); /// alloc a memory to store bitmap bitmap = (unsigned long*)calloc(sizeof(unsigned long), LONGS(image_hdr.totalblock)); if (bitmap == NULL) { log_mesg(0, 1, 1, debug, "%s, %i, not enough memory\n", __func__, __LINE__); } log_mesg(2, 0, 0, debug, "initial main bitmap pointer %p\n", bitmap); log_mesg(1, 0, 0, debug, "Initial image hdr - read bitmap table\n"); /// read and check bitmap from partition log_mesg(0, 0, 1, debug, "Calculating bitmap... Please wait... "); readbitmap(source, image_hdr, bitmap, pui); needed_size = (unsigned long long)(((image_hdr.block_size+sizeof(unsigned long))*image_hdr.usedblocks)+sizeof(image_hdr)+sizeof(char)*image_hdr.totalblock); if (opt.check) check_free_space(&dfw, needed_size); log_mesg(2, 0, 0, debug, "check main bitmap pointer %p\n", bitmap); log_mesg(1, 0, 0, debug, "Writing super block and bitmap... "); /// write image_head to image file if (write_all(&dfw, (char *)&image_hdr, sizeof(image_head), &opt) == -1) log_mesg(0, 1, 1, debug, "write image_hdr to image error: %s\n", strerror(errno)); /// write bitmap information to image file for (i = 0; i < image_hdr.totalblock; i++) { if (pc_test_bit(i, bitmap)) { bbuffer[i % sizeof(bbuffer)] = 1; } else { bbuffer[i % sizeof(bbuffer)] = 0; } if (i % sizeof(bbuffer) == sizeof(bbuffer) - 1 || i == image_hdr.totalblock - 1) { if (write_all(&dfw, bbuffer, 1 + (i % sizeof(bbuffer)), &opt) == -1) log_mesg(0, 1, 1, debug, "write bitmap to image error\n"); } } log_mesg(0, 0, 1, debug, "done!\n"); } else if (opt.restore) { unsigned long long needed_mem; log_mesg(1, 0, 0, debug, "restore image hdr - get image_head from image file\n"); log_mesg(1, 0, 1, debug, "Reading Super Block\n"); /// get image information from image file restore_image_hdr(&dfr, &opt, &image_hdr); /// check memory size if (check_mem_size(image_hdr, opt, &needed_mem) == -1) log_mesg(0, 1, 1, debug, "There is not enough free memory, partclone suggests you should have %llu bytes memory\n", needed_mem); /// alloc a memory to restore bitmap bitmap = (unsigned long*)calloc(sizeof(unsigned long), LONGS(image_hdr.totalblock)); if (bitmap == NULL) { log_mesg(0, 1, 1, debug, "%s, %i, not enough memory\n", __func__, __LINE__); } /// check the image magic if (memcmp(image_hdr.magic, IMAGE_MAGIC, IMAGE_MAGIC_SIZE)) log_mesg(0, 1, 1, debug, "This is not partclone image.\n"); /// check the file system //if (strcmp(image_hdr.fs, FS) != 0) // log_mesg(0, 1, 1, debug, "%s can't restore from the image which filesystem is %s not %s\n", argv[0], image_hdr.fs, FS); log_mesg(2, 0, 0, debug, "initial main bitmap pointer %p\n", bitmap); log_mesg(1, 0, 0, debug, "Initial image hdr - read bitmap table\n"); /// read and check bitmap from image file log_mesg(0, 0, 1, debug, "Calculating bitmap... Please wait... "); get_image_bitmap(&dfr, opt, image_hdr, bitmap); #ifndef CHKIMG /// check the dest partition size. if (opt.restore_raw_file) check_free_space(&dfw, image_hdr.device_size); else if (opt.check) check_size(&dfw, image_hdr.device_size); #endif log_mesg(2, 0, 0, debug, "check main bitmap pointer %p\n", bitmap); log_mesg(0, 0, 1, debug, "done!\n"); } else if (opt.dd || opt.domain) { unsigned long long needed_mem; log_mesg(1, 0, 0, debug, "Initial image hdr - get Super Block from partition\n"); log_mesg(1, 0, 1, debug, "Reading Super Block\n"); /// get Super Block information from partition initial_image_hdr(source, &image_hdr); /// check memory size if (check_mem_size(image_hdr, opt, &needed_mem) == -1) log_mesg(0, 1, 1, debug, "There is not enough free memory, partclone suggests you should have %llu bytes memory\n", needed_mem); strncpy(image_hdr.version, IMAGE_VERSION, VERSION_SIZE); /// alloc a memory to restore bitmap bitmap = (unsigned long*)calloc(sizeof(unsigned long), LONGS(image_hdr.totalblock)); if (bitmap == NULL) { log_mesg(0, 1, 1, debug, "%s, %i, not enough memory\n", __func__, __LINE__); } log_mesg(2, 0, 0, debug, "initial main bitmap pointer %p\n", bitmap); log_mesg(1, 0, 0, debug, "Initial image hdr - read bitmap table\n"); /// read and check bitmap from partition log_mesg(0, 0, 1, debug, "Calculating bitmap... Please wait... "); readbitmap(source, image_hdr, bitmap, pui); /// check the dest partition size. if (opt.dd && opt.check) { check_size(&dfw, image_hdr.device_size); } log_mesg(2, 0, 0, debug, "check main bitmap pointer %p\n", bitmap); log_mesg(0, 0, 1, debug, "done!\n"); } else if (opt.ddd){ unsigned long long needed_mem = 0; unsigned long long needed_size = 0; log_mesg(1, 0, 0, debug, "Initial image hdr - get Super Block from partition\n"); log_mesg(1, 0, 1, debug, "Reading Super Block\n"); /// get Super Block information from partition if (dfr != 0) initial_image_hdr(source, &image_hdr); else initial_image_hdr(target, &image_hdr); /// check memory size if (check_mem_size(image_hdr, opt, &needed_mem) == -1) log_mesg(0, 1, 1, debug, "There is not enough free memory, partclone suggests you should have %llu bytes memory\n", needed_mem); strncpy(image_hdr.version, IMAGE_VERSION, VERSION_SIZE); /// alloc a memory to restore bitmap bitmap = (unsigned long*)calloc(sizeof(unsigned long), LONGS(image_hdr.totalblock)); if (bitmap == NULL) { log_mesg(0, 1, 1, debug, "%s, %i, not enough memory\n", __func__, __LINE__); } log_mesg(2, 0, 0, debug, "initial main bitmap pointer %p\n", bitmap); log_mesg(1, 0, 0, debug, "Initial image hdr - read bitmap table\n"); /// read and check bitmap from partition log_mesg(0, 0, 1, debug, "Calculating bitmap... Please wait... "); readbitmap(source, image_hdr, bitmap, pui); /// check the dest partition size. if (opt.check) { struct stat target_stat; if ((stat(opt.target, &target_stat) != -1) && (strcmp(opt.target, "-") != 0)) { if (S_ISBLK(target_stat.st_mode)) check_size(&dfw, image_hdr.device_size); else needed_size = (unsigned long long)(((image_hdr.block_size+sizeof(unsigned long))*image_hdr.usedblocks)+sizeof(image_hdr)+sizeof(char)*image_hdr.totalblock); check_free_space(&dfw, needed_size); } } log_mesg(2, 0, 0, debug, "check main bitmap pointer %p\n", bitmap); log_mesg(0, 0, 1, debug, "done!\n"); } log_mesg(1, 0, 0, debug, "print image_head\n"); /// print option to log file if (debug) print_opt(opt); /// print image_head print_image_hdr_info(image_hdr, opt); /** * initial progress bar */ start = 0; /// start number of progress bar stop = (image_hdr.usedblocks); /// get the end of progress number, only used block log_mesg(1, 0, 0, debug, "Initial Progress bar\n"); /// Initial progress bar if (opt.no_block_detail) flag = NO_BLOCK_DETAIL; else flag = IO; progress_init(&prog, start, stop, image_hdr.totalblock, flag, image_hdr.block_size); copied = 0; /// initial number is 0 /** * thread to print progress */ pres = pthread_create(&prog_thread, NULL, thread_update_pui, NULL); if(pres) log_mesg(0, 1, 1, debug, "%s, %i, thread create error\n", __func__, __LINE__); /** * start read and write data between source and destination */ if (opt.clone) { unsigned long crc = 0xffffffffL; int block_size = image_hdr.block_size; unsigned long long blocks_total = image_hdr.totalblock; int blocks_in_buffer = block_size < opt.buffer_size ? opt.buffer_size / block_size : 1; char *read_buffer, *write_buffer; read_buffer = (char*)malloc(blocks_in_buffer * block_size); write_buffer = (char*)malloc(blocks_in_buffer * (block_size + CRC_SIZE)); if (read_buffer == NULL || write_buffer == NULL) { log_mesg(0, 1, 1, debug, "%s, %i, not enough memory\n", __func__, __LINE__); } /// write a magic string w_size = write_all(&dfw, bitmagic, 8, &opt); /// read data from the first block if (lseek(dfr, 0, SEEK_SET) == (off_t)-1) log_mesg(0, 1, 1, debug, "source seek ERROR:%s\n", strerror(errno)); log_mesg(0, 0, 0, debug, "Total block %llu\n", blocks_total); /// start clone partition to image file log_mesg(1, 0, 0, debug, "start backup data...\n"); block_id = 0; do { /// scan bitmap unsigned long long i, blocks_skip, blocks_read; off_t offset; /// skip chunk for (blocks_skip = 0; block_id + blocks_skip < blocks_total && !pc_test_bit(block_id + blocks_skip, bitmap); blocks_skip++); if (block_id + blocks_skip == blocks_total) break; if (blocks_skip) block_id += blocks_skip; /// read chunk for (blocks_read = 0; block_id + blocks_read < blocks_total && blocks_read < blocks_in_buffer && pc_test_bit(block_id + blocks_read, bitmap); blocks_read++); if (!blocks_read) break; offset = (off_t)(block_id * block_size); if (lseek(dfr, offset, SEEK_SET) == (off_t)-1) log_mesg(0, 1, 1, debug, "source seek ERROR:%s\n", strerror(errno)); r_size = read_all(&dfr, read_buffer, blocks_read * block_size, &opt); if (r_size != (int)(blocks_read * block_size)) { if ((r_size == -1) && (errno == EIO)) { if (opt.rescue) { memset(read_buffer, 0, blocks_read * block_size); for (r_size = 0; r_size < blocks_read * block_size; r_size += PART_SECTOR_SIZE) rescue_sector(&dfr, offset + r_size, read_buffer + r_size, &opt); } else log_mesg(0, 1, 1, debug, "%s", bad_sectors_warning_msg); } else log_mesg(0, 1, 1, debug, "read error: %s\n", strerror(errno)); } /// calculate crc for (i = 0; i < blocks_read; i++) { crc = crc32(crc, read_buffer + i * block_size, block_size); memcpy(write_buffer + i * (block_size + CRC_SIZE), read_buffer + i * block_size, block_size); memcpy(write_buffer + i * (block_size + CRC_SIZE) + block_size, &crc, CRC_SIZE); } /// write buffer to target w_size = write_all(&dfw, write_buffer, blocks_read * (block_size + CRC_SIZE), &opt); if (w_size != blocks_read * (block_size + CRC_SIZE)) log_mesg(0, 1, 1, debug, "image write ERROR:%s\n", strerror(errno)); /// count copied block copied += blocks_read; /// next block block_id += blocks_read; /// read or write error if (r_size + blocks_read * CRC_SIZE != w_size) log_mesg(0, 1, 1, debug, "read(%i) and write(%i) different\n", r_size, w_size); } while (1); free(write_buffer); free(read_buffer); } else if (opt.restore) { unsigned long crc = 0xffffffffL; char *read_buffer, *write_buffer; int block_size = image_hdr.block_size; unsigned long long blocks_used_fix = 0, test_block = 0; unsigned long long blocks_used = image_hdr.usedblocks; unsigned long long blocks_total = image_hdr.totalblock; int blocks_in_buffer = block_size < opt.buffer_size ? opt.buffer_size / block_size : 1; // fix some super block record incorrect for (test_block = 0; test_block < blocks_total; test_block++) if ( pc_test_bit(test_block, bitmap)) blocks_used_fix++; if (blocks_used_fix != blocks_used) blocks_used = blocks_used_fix; read_buffer = (char*)malloc(blocks_in_buffer * (block_size + 2 * CRC_SIZE)); write_buffer = (char*)malloc(blocks_in_buffer * (block_size + CRC_SIZE)); if (read_buffer == NULL || write_buffer == NULL) { log_mesg(0, 1, 1, debug, "%s, %i, not enough memory\n", __func__, __LINE__); } /// read magic string from image file and check it. if (read_all(&dfr, bitmagic_r, 8, &opt) != 8) log_mesg(0, 1, 1, debug, "read magic ERROR:%s\n", strerror(errno)); if (memcmp(bitmagic, bitmagic_r, 8)) log_mesg(0, 1, 1, debug, "can't find bitmagic\n"); #ifndef CHKIMG /// seek to the first if (lseek(dfw, opt.offset, SEEK_SET) == (off_t)-1) log_mesg(0, 1, 1, debug, "target seek ERROR:%s\n", strerror(errno)); #endif /// start restore image file to partition log_mesg(1, 0, 0, debug, "start restore data...\n"); block_id = 0; do { int i, bugcheck = 0; unsigned long crc_saved; unsigned long long blocks_written, bytes_skip; // max chunk to read using one read(2) syscall int blocks_read = copied + blocks_in_buffer < blocks_used ? blocks_in_buffer : blocks_used - copied; if (!blocks_read) break; // read chunk from image r_size = read_all(&dfr, read_buffer, blocks_read * (block_size + CRC_SIZE), &opt); if (r_size != blocks_read * (block_size + CRC_SIZE)) log_mesg(0, 1, 1, debug, "read ERROR:%s\n", strerror(errno)); // read buffer is the follows: // ... // write buffer should be the follows: // ... // fill up write buffer, check crc recheck: crc_saved = crc; for (i = 0; i < blocks_read; i++) { memcpy(write_buffer + i * block_size, read_buffer + i * (block_size + CRC_SIZE), block_size); if (opt.ignore_crc) continue; // check crc crc = crc32(crc, read_buffer + i * (block_size + CRC_SIZE), block_size); if (memcmp(read_buffer + i * (block_size + CRC_SIZE) + block_size, &crc, CRC_SIZE)) { if (bugcheck) log_mesg(0, 1, 1, debug, "CRC error, block_id=%llu...\n ", block_id + i); else log_mesg(1, 0, 0, debug, "CRC Check error. 64bit bug before v0.1.0 (Rev:250M), " "trying enlarge crc size and recheck again...\n"); // try to read (blocks_read * CRC_SIZE) bytes to the end of read_buffer if (read_all(&dfr, read_buffer + blocks_read * (block_size + CRC_SIZE), blocks_read * CRC_SIZE, &opt) != blocks_read * CRC_SIZE) { log_mesg(0, 1, 1, debug, "read CRC error: %s, please check your image file.\n", strerror(errno)); } // reshape read_buffer and try to check crc again if (i > 0) { // first block correct // i.e. read buffer is the follows: // ... for (i = 0; i < blocks_read; i++) { memcpy(write_buffer + i * (block_size + CRC_SIZE), read_buffer + i * (block_size + 2*CRC_SIZE), block_size + CRC_SIZE); } } else { // first block incorrect // i.e. read buffer is the follows: // ... for (i = 0; i < blocks_read; i++) { memcpy(write_buffer + i * (block_size + CRC_SIZE), read_buffer + i * (block_size + 2*CRC_SIZE) + CRC_SIZE, block_size + CRC_SIZE); } } memcpy(read_buffer, write_buffer, blocks_read * (block_size + CRC_SIZE)); crc = crc_saved; bugcheck = 1; goto recheck; } } blocks_written = 0; do { int blocks_write; /// count bytes to skip for (bytes_skip = 0; block_id < blocks_total && !pc_test_bit(block_id, bitmap); block_id++, bytes_skip += block_size); #ifndef CHKIMG /// skip empty blocks if (bytes_skip > 0 && lseek(dfw, (off_t)bytes_skip, SEEK_CUR) == (off_t)-1) log_mesg(0, 1, 1, debug, "target seek ERROR:%s\n", strerror(errno)); #endif /// blocks to write for (blocks_write = 0; block_id + blocks_write < blocks_total && blocks_written + blocks_write < blocks_read && pc_test_bit(block_id + blocks_write, bitmap); blocks_write++); #ifndef CHKIMG // write blocks if (blocks_write > 0) { w_size = write_all(&dfw, write_buffer + blocks_written * block_size, blocks_write * block_size, &opt); if (w_size != blocks_write * block_size) { if (!opt.skip_write_error) log_mesg(0, 1, 1, debug, "write block %llu ERROR:%s\n", block_id + blocks_written, strerror(errno)); else log_mesg(0, 0, 1, debug, "skip write block %llu error:%s\n", block_id + blocks_written, strerror(errno)); } } #endif blocks_written += blocks_write; block_id += blocks_write; copied += blocks_write; } while (blocks_written < blocks_read); } while(1); free(write_buffer); free(read_buffer); #ifndef CHKIMG /// restore_raw_file option if (opt.restore_raw_file && !pc_test_bit(blocks_total - 1, bitmap)) { if (ftruncate(dfw, (off_t)(blocks_total * block_size)) == -1) log_mesg(0, 0, 1, debug, "ftruncate ERROR:%s\n", strerror(errno)); } #endif } else if (opt.dd) { char *buffer; int block_size = image_hdr.block_size; unsigned long long blocks_total = image_hdr.totalblock; int blocks_in_buffer = block_size < opt.buffer_size ? opt.buffer_size / block_size : 1; buffer = (char*)malloc(blocks_in_buffer * block_size); if (buffer == NULL) { log_mesg(0, 1, 1, debug, "%s, %i, not enough memory\n", __func__, __LINE__); } block_id = 0; if (lseek(dfr, 0, SEEK_SET) == (off_t)-1) log_mesg(0, 1, 1, debug, "source seek ERROR:%d\n", strerror(errno)); log_mesg(0, 0, 0, debug, "Total block %llu\n", blocks_total); /// start clone partition to partition log_mesg(1, 0, 0, debug, "start backup data device-to-device...\n"); do { /// scan bitmap unsigned long long blocks_skip, blocks_read; off_t offset; /// skip chunk for (blocks_skip = 0; block_id + blocks_skip < blocks_total && !pc_test_bit(block_id + blocks_skip, bitmap); blocks_skip++); if (block_id + blocks_skip == blocks_total) break; if (blocks_skip) block_id += blocks_skip; /// read chunk from source for (blocks_read = 0; block_id + blocks_read < blocks_total && blocks_read < blocks_in_buffer && pc_test_bit(block_id + blocks_read, bitmap); blocks_read++); if (!blocks_read) break; offset = (off_t)(block_id * block_size); if (lseek(dfr, offset, SEEK_SET) == (off_t)-1) log_mesg(0, 1, 1, debug, "source seek ERROR:%s\n", strerror(errno)); if (lseek(dfw, offset + opt.offset, SEEK_SET) == (off_t)-1) log_mesg(0, 1, 1, debug, "target seek ERROR:%s\n", strerror(errno)); r_size = read_all(&dfr, buffer, blocks_read * block_size, &opt); if (r_size != (int)(blocks_read * block_size)) { if ((r_size == -1) && (errno == EIO)) { if (opt.rescue) { memset(buffer, 0, blocks_read * block_size); for (r_size = 0; r_size < blocks_read * block_size; r_size += PART_SECTOR_SIZE) rescue_sector(&dfr, offset + r_size, buffer + r_size, &opt); } else log_mesg(0, 1, 1, debug, "%s", bad_sectors_warning_msg); } else log_mesg(0, 1, 1, debug, "source read ERROR %s\n", strerror(errno)); } /// write buffer to target w_size = write_all(&dfw, buffer, blocks_read * block_size, &opt); if (w_size != (int)(blocks_read * block_size)) { if (opt.skip_write_error) log_mesg(0, 0, 1, debug, "skip write block %lli error:%s\n", block_id, strerror(errno)); else log_mesg(0, 1, 1, debug, "write block %lli ERROR:%s\n", block_id, strerror(errno)); } /// count copied block copied += blocks_read; /// next block block_id += blocks_read; /// read or write error if (r_size != w_size) { if (opt.skip_write_error) log_mesg(0, 0, 1, debug, "read and write different\n"); else log_mesg(0, 1, 1, debug, "read and write different\n"); } } while (1); free(buffer); /// restore_raw_file option if (opt.restore_raw_file && !pc_test_bit(blocks_total - 1, bitmap)) { if (ftruncate(dfw, (off_t)(blocks_total * block_size)) == -1) log_mesg(0, 0, 1, debug, "ftruncate ERROR:%s\n", strerror(errno)); } } else if (opt.domain) { int cmp, nx_current = 0; unsigned long long next_block_id = 0; log_mesg(0, 0, 0, debug, "Total block %llu\n", image_hdr.totalblock); log_mesg(1, 0, 0, debug, "start writing domain log...\n"); // write domain log comment and status line dprintf(dfw, "# Domain logfile created by %s v%s\n", EXECNAME, VERSION); dprintf(dfw, "# Source: %s\n", opt.source); dprintf(dfw, "# Offset: 0x%08llX\n", opt.offset_domain); dprintf(dfw, "# current_pos current_status\n"); dprintf(dfw, "0x%08llX ?\n", opt.offset_domain + (image_hdr.totalblock * image_hdr.block_size)); dprintf(dfw, "# pos size status\n"); // start logging the used/unused areas cmp = pc_test_bit(0, bitmap); for (block_id = 0; block_id <= image_hdr.totalblock; block_id++) { if (block_id < image_hdr.totalblock) { nx_current = pc_test_bit(block_id, bitmap); if (nx_current) copied++; } else nx_current = -1; if (nx_current != cmp) { dprintf(dfw, "0x%08llX 0x%08llX %c\n", opt.offset_domain + (next_block_id * image_hdr.block_size), (block_id - next_block_id) * image_hdr.block_size, cmp ? '+' : '?'); next_block_id = block_id; cmp = nx_current; } // don't bother updating progress } /// end of for } else if (opt.ddd) { char *buffer; int block_size = image_hdr.block_size; unsigned long long blocks_total = image_hdr.totalblock; int blocks_in_buffer = block_size < opt.buffer_size ? opt.buffer_size / block_size : 1; buffer = (char*)malloc(blocks_in_buffer * block_size); if (buffer == NULL) { log_mesg(0, 1, 1, debug, "%s, %i, not enough memory\n", __func__, __LINE__); } block_id = 0; log_mesg(0, 0, 0, debug, "Total block %llu\n", blocks_total); /// start clone partition to partition log_mesg(1, 0, 0, debug, "start backup data device-to-device...\n"); do { /// scan bitmap unsigned long long blocks_read; /// read chunk from source for (blocks_read = 0; block_id + blocks_read < blocks_total && blocks_read < blocks_in_buffer && pc_test_bit(block_id + blocks_read, bitmap); blocks_read++); if (!blocks_read) break; r_size = read_all(&dfr, buffer, blocks_read * block_size, &opt); if (r_size != (int)(blocks_read * block_size)) { if ((r_size == -1) && (errno == EIO)) { if (opt.rescue) { memset(buffer, 0, blocks_read * block_size); for (r_size = 0; r_size < blocks_read * block_size; r_size += PART_SECTOR_SIZE) rescue_sector(&dfr, r_size, buffer + r_size, &opt); } else log_mesg(0, 1, 1, debug, "%s", bad_sectors_warning_msg); } else if (r_size == 0){ // done for ddd /// write buffer to target w_size = write_all(&dfw, buffer, rescue_write_size, &opt); break; } else log_mesg(0, 1, 1, debug, "source read ERROR %s\n", strerror(errno)); } /// write buffer to target w_size = write_all(&dfw, buffer, blocks_read * block_size, &opt); if (w_size != (int)(blocks_read * block_size)) { if (opt.skip_write_error) log_mesg(0, 0, 1, debug, "skip write block %lli error:%s\n", block_id, strerror(errno)); else log_mesg(0, 1, 1, debug, "write block %lli ERROR:%s\n", block_id, strerror(errno)); } /// count copied block copied += blocks_read; /// next block block_id += blocks_read; /// read or write error if (r_size != w_size) { if (opt.skip_write_error) log_mesg(0, 0, 1, debug, "read and write different\n"); else log_mesg(0, 1, 1, debug, "read and write different\n"); } } while (1); free(buffer); /// restore_raw_file option if (opt.restore_raw_file && !pc_test_bit(blocks_total - 1, bitmap)) { if (ftruncate(dfw, (off_t)(blocks_total * block_size)) == -1) log_mesg(0, 0, 1, debug, "ftruncate ERROR:%s\n", strerror(errno)); } } done = 1; pres = pthread_join(prog_thread, &p_result); if(pres) log_mesg(0, 1, 1, debug, "%s, %i, thread join error\n", __func__, __LINE__); update_pui(&prog, copied, block_id, done); #ifndef CHKIMG sync_data(dfw, &opt); #endif print_finish_info(opt); /// close source close(dfr); /// close target if (dfw != -1) close(dfw); /// free bitmp free(bitmap); close_pui(pui); #ifndef CHKIMG fprintf(stderr, "Cloned successfully.\n"); #else printf("Checked successfully.\n"); #endif if (opt.debug) close_log(); #ifdef MEMTRACE muntrace(); #endif return 0; /// finish } void *thread_update_pui(void *arg) { while (!done) { if (!opt.quiet) update_pui(&prog, copied, block_id, done); sleep(opt.fresh); } pthread_exit("exit"); } partclone-0.2.86/src/minixclone.c000066400000000000000000000202521262102574200167000ustar00rootroot00000000000000/** * minixclone.c - part of Partclone project * * Copyright (c) 2007~ Thomas Tsai * * read minix super block and bitmap * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. **/ #include #include #include #include #include #include #include #include "partclone.h" #include "progress.h" #include "fs_common.h" #include "minixclone.h" char *super_block_buffer; #define inode_in_use(x, map) (isset(map,(x)) != 0) #define Super (*(struct minix_super_block *) super_block_buffer) #define Super3 (*(struct minix3_super_block *) super_block_buffer) #define MAGIC (Super.s_magic) #define MAGIC3 (Super3.s_magic) int dev; int fs_version = 1; char *EXECNAME = "partclone.minix"; extern fs_cmd_opt fs_opt; static inline unsigned long get_max_size(void) { switch (fs_version) { case 3: return (unsigned long)Super3.s_max_size; default: return (unsigned long)Super.s_max_size; } } static inline unsigned long get_ninodes(void) { switch (fs_version) { case 3: return Super3.s_ninodes; default: return (unsigned long)Super.s_ninodes; } } static inline unsigned long get_nzones(void) { switch (fs_version) { case 3: return (unsigned long)Super3.s_zones; case 2: return (unsigned long)Super.s_zones; default: return (unsigned long)Super.s_nzones; } } static inline unsigned long get_nimaps(void) { switch (fs_version) { case 3: return (unsigned long)Super3.s_imap_blocks; default: return (unsigned long)Super.s_imap_blocks; } } static inline unsigned long get_nzmaps(void) { switch (fs_version) { case 3: return (unsigned long)Super3.s_zmap_blocks; default: return (unsigned long)Super.s_zmap_blocks; } } static inline unsigned long get_zone_size(void) { switch (fs_version) { case 3: return (unsigned long)Super3.s_log_zone_size; default: return (unsigned long)Super.s_log_zone_size; } } static inline unsigned long get_block_size(void) { switch (fs_version) { case 3: return (unsigned long)Super3.s_blocksize; default: return MINIX_BLOCK_SIZE; } } static inline unsigned long get_first_zone(void) { switch (fs_version) { case 3: return (unsigned long)Super3.s_firstdatazone; default: return (unsigned long)Super.s_firstdatazone; } } static void fs_open(char *device) { dev = open(device,O_RDONLY); log_mesg(0, 0, 0, fs_opt.debug, "%s: open minix fs\n", __FILE__); if (MINIX_BLOCK_SIZE != lseek(dev, MINIX_BLOCK_SIZE, SEEK_SET)) log_mesg(0, 1, 1, fs_opt.debug, "%s: seek failed\n", __FILE__); super_block_buffer = calloc(1, MINIX_BLOCK_SIZE); if (!super_block_buffer) log_mesg(0, 1, 1, fs_opt.debug, "%s: unable to alloc buffer for superblock", __FILE__); if (MINIX_BLOCK_SIZE != read(dev, super_block_buffer, MINIX_BLOCK_SIZE)) log_mesg(0, 1, 1, fs_opt.debug, "%s: unable to read super block", __FILE__); } static void fs_close(){ close(dev); } static unsigned long count_used_block(){ unsigned long zones = get_nzones(); unsigned long imaps = get_nimaps(); unsigned long zmaps = get_nzmaps(); char *inode_map; char *zone_map; ssize_t rc; unsigned long test_block = 0, test_zone = 0; unsigned long used_block = 0; unsigned long block_size = get_block_size(); if (fs_version == 3){ if (lseek(dev, block_size*2, SEEK_SET) != 8192) log_mesg(0, 1, 1, fs_opt.debug, "%s: seek failed", __FILE__); } inode_map = (char *)calloc(sizeof(char), imaps * block_size); if (!inode_map) log_mesg(0, 1, 1, fs_opt.debug, "%s: Unable to allocate buffer for inode map", __FILE__); zone_map = (char *)calloc(sizeof(char), zmaps * block_size); if (!inode_map) log_mesg(0, 1, 1, fs_opt.debug, "%s: Unable to allocate buffer for zone map", __FILE__); rc = read(dev, inode_map, imaps * block_size); if (rc < 0 || imaps * block_size != (size_t) rc) log_mesg(0, 1, 1, fs_opt.debug, "%s: Unable to read inode map", __FILE__); rc = read(dev, zone_map, zmaps * block_size); if (rc < 0 || zmaps * block_size != (size_t) rc) log_mesg(0, 1, 1, fs_opt.debug, "%s: Unable to read zone map", __FILE__); for (test_block = 0; test_block < zones; test_block++){ test_zone = test_block - get_first_zone()+1; if ((test_zone < 0) || (test_zone > zones+get_first_zone())) test_zone = 0; if(isset(zone_map,test_zone)){ log_mesg(3, 0, 0, fs_opt.debug, "%s: test_block %lu in use\n", __FILE__, test_block); used_block++; }else{ log_mesg(3, 0, 0, fs_opt.debug, "%s: test_block %lu not use\n", __FILE__, test_block); } } free(zone_map); free(inode_map); return used_block; } extern void initial_image_hdr(char* device, image_head* image_hdr){ fs_open(device); if (MAGIC == MINIX_SUPER_MAGIC) { fs_version = 1; } else if (MAGIC == MINIX_SUPER_MAGIC2) { fs_version = 1; } else if (MAGIC == MINIX2_SUPER_MAGIC) { fs_version = 2; } else if (MAGIC == MINIX2_SUPER_MAGIC2) { fs_version = 2; } else if (MAGIC3 == MINIX3_SUPER_MAGIC){ fs_version = 3; } else log_mesg(0, 1, 1, fs_opt.debug, "%s: bad magic number in super-block", __FILE__); log_mesg(0, 0, 0, fs_opt.debug, "%s: get_first_zone %lu\n", __FILE__, get_first_zone()); log_mesg(0, 0, 0, fs_opt.debug, "%s: get_nzones %lu\n", __FILE__, get_nzones()); log_mesg(0, 0, 0, fs_opt.debug, "%s: zones map size %lu\n", __FILE__, get_nzmaps()); strncpy(image_hdr->magic, IMAGE_MAGIC, IMAGE_MAGIC_SIZE); strncpy(image_hdr->fs, minix_MAGIC, FS_MAGIC_SIZE); image_hdr->block_size = get_block_size(); image_hdr->totalblock = get_nzones(); image_hdr->usedblocks = count_used_block(); image_hdr->device_size = get_nzones()*get_block_size(); fs_close(); } extern void readbitmap(char* device, image_head image_hdr, unsigned long* bitmap, int pui){ unsigned long zones = get_nzones(); unsigned long imaps = get_nimaps(); unsigned long zmaps = get_nzmaps(); char * inode_map; char * zone_map; ssize_t rc; unsigned long test_block = 0, test_zone = 0; fs_open(device); unsigned long block_size = get_block_size(); if (fs_version == 3){ if (lseek(dev, block_size*2, SEEK_SET) != 8192) log_mesg(0, 1, 1, fs_opt.debug, "%s: seek failed", __FILE__); } inode_map = (char *)calloc(sizeof(char), imaps * block_size); if (!inode_map) log_mesg(0, 1, 1, fs_opt.debug, "%s: Unable to allocate buffer for inode map", __FILE__); zone_map = (char *)calloc(sizeof(char), zmaps * block_size); if (!inode_map) log_mesg(0, 1, 1, fs_opt.debug, "%s: Unable to allocate buffer for zone map", __FILE__); rc = read(dev, inode_map, imaps * block_size); if (rc < 0 || imaps * block_size != (size_t) rc) log_mesg(0, 1, 1, fs_opt.debug, "%s: Unable to read inode map", __FILE__); rc = read(dev, zone_map, zmaps * block_size); if (rc < 0 || zmaps * block_size != (size_t) rc) log_mesg(0, 1, 1, fs_opt.debug, "%s: Unable to read zone map", __FILE__); log_mesg(0, 0, 0, fs_opt.debug, "%s: %ld blocks\n", __FILE__, zones); log_mesg(0, 0, 0, fs_opt.debug, "%s: log2 block/zone: %lu\n", __FILE__, get_zone_size()); log_mesg(0, 0, 0, fs_opt.debug, "%s: Zonesize=%d\n", __FILE__,block_size< zones+get_first_zone())) test_zone = 0; if(isset(zone_map,test_zone)){ log_mesg(3, 0, 0, fs_opt.debug, "%s: test_block %lu in use\n", __FILE__, test_block); pc_set_bit(test_block, bitmap); }else{ log_mesg(3, 0, 0, fs_opt.debug, "%s: test_block %lu not use\n", __FILE__, test_block); } } free(zone_map); free(inode_map); fs_close(); } partclone-0.2.86/src/minixclone.h000066400000000000000000000051361262102574200167110ustar00rootroot00000000000000/** * minixclone.h - part of Partclone project * * Copyright (c) 2007~ Thomas Tsai * * read hfsplus super block and bitmap * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ #include struct minix_inode { uint16_t i_mode; uint16_t i_uid; uint32_t i_size; uint32_t i_time; uint8_t i_gid; uint8_t i_nlinks; uint16_t i_zone[9]; }; struct minix2_inode { uint16_t i_mode; uint16_t i_nlinks; uint16_t i_uid; uint16_t i_gid; uint32_t i_size; uint32_t i_atime; uint32_t i_mtime; uint32_t i_ctime; uint32_t i_zone[10]; }; struct minix_super_block { uint16_t s_ninodes; uint16_t s_nzones; uint16_t s_imap_blocks; uint16_t s_zmap_blocks; uint16_t s_firstdatazone; uint16_t s_log_zone_size; uint32_t s_max_size; uint16_t s_magic; uint16_t s_state; uint32_t s_zones; }; /* V3 minix super-block data on disk */ struct minix3_super_block { uint32_t s_ninodes; uint16_t s_pad0; uint16_t s_imap_blocks; uint16_t s_zmap_blocks; uint16_t s_firstdatazone; uint16_t s_log_zone_size; uint16_t s_pad1; uint32_t s_max_size; uint32_t s_zones; uint16_t s_magic; uint16_t s_pad2; uint16_t s_blocksize; uint8_t s_disk_version; }; /* * Minix subpartitions are always within primary dos partition. */ #define MINIX_MAXPARTITIONS 4 #define MINIX_BLOCK_SIZE_BITS 10 #define MINIX_BLOCK_SIZE (1 << MINIX_BLOCK_SIZE_BITS) #define MINIX_NAME_MAX 255 /* # chars in a file name */ #define MINIX_MAX_INODES 65535 #define MINIX_INODES_PER_BLOCK ((MINIX_BLOCK_SIZE)/(sizeof (struct minix_inode))) #define MINIX2_INODES_PER_BLOCK ((MINIX_BLOCK_SIZE)/(sizeof (struct minix2_inode))) /* minix_super_block.s_state */ #define MINIX_VALID_FS 0x0001 /* Clean fs. */ #define MINIX_ERROR_FS 0x0002 /* fs has errors. */ #define MINIX_SUPER_MAGIC 0x137F /* original minix fs */ #define MINIX_SUPER_MAGIC2 0x138F /* minix fs, 30 char names */ #define MINIX2_SUPER_MAGIC 0x2468 /* minix V2 fs */ #define MINIX2_SUPER_MAGIC2 0x2478 /* minix V2 fs, 30 char names */ #define MINIX3_SUPER_MAGIC 0x4d5a /* minix V3 fs (60 char names) */ /// read super block and write to image head extern void initial_image_hdr(char* device, image_head* image_hdr); /// readbitmap - cread and heck bitmap, reference dumpe2fs extern void readbitmap(char* device, image_head image_hdr, unsigned long* bitmap, int pui); partclone-0.2.86/src/nilfsclone.c000066400000000000000000000130021262102574200166620ustar00rootroot00000000000000/** * nilfsclone.c - part of Partclone project * * Copyright (c) 2015~ Thomas Tsai * * read nilfs super block and bitmap * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ #include #include #include #include #include //#include "nilfs/nilfs.h" //#include "nilfs/util.h" #include #define LSSU_NSEGS 512 #include "partclone.h" #include "nilfsclone.h" #include "progress.h" #include "fs_common.h" int mnt_x=0; char *mnt_path = "/tmp/partclone_mnt/"; //fixme struct nilfs_super_block *sbp; struct nilfs *nilfs; char *EXECNAME = "partclone.nilfs"; extern fs_cmd_opt fs_opt; static struct nilfs_suinfo suinfos[LSSU_NSEGS]; int blocks_per_segment; unsigned long long total_block; ///set useb block static void set_bitmap(unsigned long* bitmap, uint64_t segm, uint64_t count){ uint64_t block; uint64_t pos_block; uint64_t block_end; log_mesg(3, 0, 0, fs_opt.debug, "%s: segment: %llu count %llu\n", __FILE__, segm, count); if (segm*blocks_per_segment + count > total_block) { log_mesg(1, 0, 0, fs_opt.debug, "%s: block(%llu) larger than total blocks(%llu), skip it.\n", __FILE__, segm, total_block); return; } pos_block = segm*blocks_per_segment; block_end = (segm+1)*blocks_per_segment; log_mesg(3, 0, 0, fs_opt.debug, "%s: block offset: %llu block count: %llu\n",__FILE__, pos_block, block_end); for(block = pos_block; block < block_end; block++){ log_mesg(3, 0, 0, fs_opt.debug, "%s: block %i is used\n",__FILE__, block); pc_set_bit(block, bitmap); } } static ssize_t lssu_print_suinfo(struct nilfs *nilfs, __u64 segnum, ssize_t nsi, __u64 protseq, unsigned long* bitmap) { ssize_t i, n = 0; int all = 1; for (i = 0; i < nsi; i++, segnum++) { if (!all && nilfs_suinfo_clean(&suinfos[i])) continue; log_mesg(3, 0, 0, fs_opt.debug, "%s: seg %llu, %c %c %c , %i\n", __FILE__, (unsigned long long)segnum, nilfs_suinfo_active(&suinfos[i]) ? 'a' : '-', nilfs_suinfo_dirty(&suinfos[i]) ? 'd' : '-', nilfs_suinfo_error(&suinfos[i]) ? 'e' : '-', suinfos[i].sui_nblocks); if (nilfs_suinfo_active(&suinfos[i]) || nilfs_suinfo_dirty(&suinfos[i])){ set_bitmap(bitmap, (unsigned long long)segnum, suinfos[i].sui_nblocks); } n++; } return n; } static int lssu_list_suinfo(struct nilfs *nilfs, unsigned long* bitmap) { struct nilfs_sustat sustat; __u64 segnum, rest, count; ssize_t nsi, n; if (nilfs_get_sustat(nilfs, &sustat) < 0) return 1; segnum = 0; rest = sustat.ss_nsegs; for ( ; rest > 0 && segnum < sustat.ss_nsegs; rest -= n) { count = min_t(__u64, rest, LSSU_NSEGS); nsi = nilfs_get_suinfo(nilfs, segnum, suinfos, count); if (nsi < 0) return 1; n = lssu_print_suinfo(nilfs, segnum, nsi, sustat.ss_prot_seq, bitmap); segnum += nsi; } return 0; } /// open device static void fs_open(char* device) { int open_flags; int mkstatus = 0; struct stat st; log_mesg(2, 0, 0, fs_opt.debug, "%s: nilfs_mount\n", __FILE__); if (stat(mnt_path, &st) != 0) { if (mkdir(mnt_path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0 && errno != EEXIST) { log_mesg(0, 1, 1, fs_opt.debug, "%s: cannot create directory on %s\n", __FILE__, mnt_path); } } else if (!S_ISDIR(st.st_mode)) { log_mesg(0, 1, 1, fs_opt.debug, "%s: error ENOTDIR cannot create directory on %s\n", __FILE__, strerror(mkstatus), mnt_path); } mnt_x = mount(device, mnt_path, "nilfs2", MS_MGC_VAL | MS_RDONLY | MS_NOSUID, ""); open_flags = NILFS_OPEN_RDONLY | NILFS_OPEN_RAW; nilfs = nilfs_open(device, NULL, open_flags); if (nilfs == NULL) { umount(mnt_path); log_mesg(0, 1, 1, fs_opt.debug, "%s: cannot open NILFS on %s: %m\n", __FILE__, device ? : "device"); } log_mesg(2, 0, 0, fs_opt.debug, "%s: nilfs_mount done\n", __FILE__); } /// close device static void fs_close() { log_mesg(2, 0, 0, fs_opt.debug, "%s: nilfs_umount\n", __FILE__); nilfs_close(nilfs); umount(mnt_path); log_mesg(2, 0, 0, fs_opt.debug, "%s: nilfs_umount done\n", __FILE__); } /// readbitmap - read bitmap extern void readbitmap(char* device, image_head image_hdr, unsigned long* bitmap, int pui) { int start = 0; int bit_size = 1; int status = 0; fs_open(device); /// init progress progress_bar prog; /// progress_bar structure defined in progress.h progress_init(&prog, start, image_hdr.totalblock, image_hdr.totalblock, BITMAP, bit_size); blocks_per_segment = nilfs_get_blocks_per_segment(nilfs); total_block = image_hdr.totalblock; status = lssu_list_suinfo(nilfs, bitmap); if (status == 1 ){ log_mesg(2, 0, 0, fs_opt.debug, "%s: nilfs list suinfo got fail\n", __FILE__); } fs_close(); /// update progress update_pui(&prog, 1, 1, 1); } /// read super block and write to image head extern void initial_image_hdr(char* device, image_head* image_hdr) { fs_open(device); sbp = nilfs->n_sb; strncpy(image_hdr->magic, IMAGE_MAGIC, IMAGE_MAGIC_SIZE); strncpy(image_hdr->fs, nilfs_MAGIC, FS_MAGIC_SIZE); image_hdr->block_size = nilfs_get_block_size(nilfs); image_hdr->totalblock = sbp->s_dev_size / image_hdr->block_size; image_hdr->usedblocks = image_hdr->totalblock - sbp->s_free_blocks_count; image_hdr->device_size = sbp->s_dev_size; fs_close(); } partclone-0.2.86/src/nilfsclone.h000066400000000000000000000015261262102574200166770ustar00rootroot00000000000000/** * nilfsclone.h - part of Partclone project * * Copyright (c) 2015~ Thomas Tsai * * read nilfs super block and bitmap * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ #include #include #include typedef __u64 __be64; #define min_t(type, x, y) \ ({ type __x = (x); type __y = (y); __x < __y ? __x : __y; }) /// readbitmap - cread and heck bitmap, reference dumpe2fs extern void readbitmap(char* device, image_head image_hdr, unsigned long* bitmap, int pui); /// read super block and write to image head extern void initial_image_hdr(char* device, image_head* image_hdr); partclone-0.2.86/src/ntfsclone-ng.c000066400000000000000000000261411262102574200171330ustar00rootroot00000000000000/** * ntfsclone.c - part of Partclone project * * Copyright (c) 2007~ Thomas Tsai * * read ntfs super block and bitmap * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define NTFS_DO_NOT_CHECK_ENDIANS #define NTFS_MAX_CLUSTER_SIZE 65536 #ifdef NTFS3G #include #include #include #include #else #include #include #include #include #endif #include "partclone.h" #include "ntfsclone-ng.h" #include "progress.h" #include "fs_common.h" /// define mount flag #ifdef NTFS_MNT_RDONLY #define LIBNTFS_VER_10 1 #else #define NTFS_MNT_RDONLY 1 #define LIBNTFS_VER_9 1 #endif char *EXECNAME = "partclone.ntfs"; extern fs_cmd_opt fs_opt; ntfs_volume *ntfs; /******************************************************** * Routines for counting attributes free bits. * * Used to count and verify number of free clusters * as per ntfs volume $BitMap. * * Copied from ntfs-3g 2009.11.14 source code: * ********************************************************/ /* Below macros are 32-bit ready. */ #define BCX(x) ((x) - (((x) >> 1) & 0x77777777) - \ (((x) >> 2) & 0x33333333) - \ (((x) >> 3) & 0x11111111)) #define BITCOUNT(x) (((BCX(x) + (BCX(x) >> 4)) & 0x0F0F0F0F) % 255) #ifndef NTFS3G static u8 *ntfs_init_lut256(void) { int i; u8 *lut; lut = (u8 *)ntfs_malloc(256); if (lut) for(i = 0; i < 256; i++) *(lut + i) = 8 - BITCOUNT(i); return lut; } static s64 ntfs_attr_get_free_bits(ntfs_attr *na) { u8 *buf, *lut; s64 br = 0; s64 total = 0; s64 nr_free = 0; lut = ntfs_init_lut256(); if (!lut) return -1; buf = ntfs_malloc(65536); if (!buf) goto out; while (1) { u32 *p; br = ntfs_attr_pread(na, total, 65536, buf); if (br <= 0) break; total += br; p = (u32 *)buf + br / 4 - 1; for (; (u8 *)p >= buf; p--) { nr_free += lut[ *p & 255] + lut[(*p >> 8) & 255] + lut[(*p >> 16) & 255] + lut[(*p >> 24) ]; } switch (br % 4) { case 3: nr_free += lut[*(buf + br - 3)]; case 2: nr_free += lut[*(buf + br - 2)]; case 1: nr_free += lut[*(buf + br - 1)]; } } free(buf); out: free(lut); if (!total || br < 0) return -1; return nr_free; } /* End of ntfs-3g routines code copy */ /*********************************************************/ #endif /// open device static void fs_open(char* device){ int err; unsigned long long device_size, volume_size; ntfs = ntfs_mount(device, NTFS_MNT_RDONLY); if (!ntfs) { err = errno; log_mesg(0, 1, 1, fs_opt.debug, "%s: NOT NTFS partition, ntfs mount error %i\n", __FILE__, err); } else { if(fs_opt.ignore_fschk){ log_mesg(1, 0, 0, fs_opt.debug, "%s: Ignore filesystem check\n", __FILE__); }else{ if (ntfs->flags & VOLUME_IS_DIRTY) { log_mesg(0, 1, 1, fs_opt.debug, "%s: NTFS Volume '%s' is scheduled for a check or it was shutdown\nuncleanly. Please boot Windows or fix it by fsck.\n", __FILE__, device); } else { log_mesg(3, 0, 0, fs_opt.debug, "%s: NTFS Volume '%s' is clean\n", __FILE__, device); } } if (NTFS_MAX_CLUSTER_SIZE < ntfs->cluster_size) { log_mesg(0, 1, 1, fs_opt.debug, "%s: NTFS Cluster size %"PRIu32" is too large!\n", __FILE__, ntfs->cluster_size); } else { log_mesg(3, 0, 0, fs_opt.debug, "%s: NTFS Cluster size is right!\n", __FILE__); } log_mesg(3, 0, 0, fs_opt.debug, "%s: NTFS volume version: %d.%d\n", __FILE__, ntfs->major_ver, ntfs->minor_ver); if (!ntfs_version_is_supported(ntfs)) { log_mesg(3, 0, 0, fs_opt.debug, "%s: libntfs open/mount %s as ntfs successfull\n", __FILE__, device); } else { log_mesg(0, 1, 1, fs_opt.debug, "%s: Unknown NTFS version\n", __FILE__); } // Initialize free clusters metric #ifdef NTFS3G ntfs->free_clusters = ntfs_attr_get_free_bits(ntfs->lcnbmp_na); if ( ntfs->free_clusters < 0 || ntfs->free_clusters >= ntfs->nr_clusters) { log_mesg(0, 1, 1, fs_opt.debug, "%s: Bad number of free (%"PRId64") or total (%"PRId64") clusters!\n", __FILE__, ntfs->free_clusters, ntfs->nr_clusters); } #else ntfs->nr_free_clusters = ntfs_attr_get_free_bits(ntfs->lcnbmp_na); if ( ntfs->nr_free_clusters < 0 || ntfs->nr_free_clusters >= ntfs->nr_clusters) { log_mesg(0, 1, 1, fs_opt.debug, "%s: Bad number of free (%ld) or total (%"PRId64") clusters!\n", __FILE__, ntfs->nr_free_clusters, ntfs->nr_clusters); } #endif device_size = ntfs_device_size_get(ntfs->dev, 1); volume_size = ntfs->nr_clusters * ntfs->cluster_size; log_mesg(3, 0, 0, fs_opt.debug, "%s: Cluster size\t: %"PRIu32"\n", __FILE__, ntfs->cluster_size); log_mesg(3, 0, 0, fs_opt.debug, "%s: Volume size\t: %"PRIu32" * %"PRId64" + 512 = %llu + 512 = %llu\n", __FILE__, ntfs->cluster_size, ntfs->nr_clusters, volume_size, (volume_size+512) ); log_mesg(3, 0, 0, fs_opt.debug, "%s: Device size\t: %llu\n", __FILE__, device_size); if (device_size < volume_size) { log_mesg(0, 1, 1, fs_opt.debug, "%s: Current NTFS volume size is bigger than the device size (%llu)!\nCorrupt partition table or incorrect device partitioning?\n", __FILE__, device_size); } } } /// close device static void fs_close(){ int ret = ntfs_umount(ntfs, 0); if (ret != 0) { log_mesg(0, 0, 1, fs_opt.debug, "%s: NTFS unmount error %i!\n", __FILE__, errno); } } /// readbitmap - read bitmap extern void readbitmap(char* device, image_head image_hdr, unsigned long* bitmap, int pui) { unsigned char *ntfs_bitmap; unsigned long long current_block, used_block, free_block, pos; long long int count; unsigned long bitmap_size; int start = 0; int bit_size = 1; fs_open(device); bitmap_size = (ntfs->nr_clusters + 7) / 8; if (bitmap_size > ntfs->lcnbmp_na->data_size) { log_mesg(0, 1, 1, fs_opt.debug, "%s: calculated bitmap size (%lu) > lcnbmp_na->data_size (%"PRId64")\n", __FILE__, bitmap_size, ntfs->lcnbmp_na->data_size); } ntfs_bitmap = (unsigned char*)malloc(bitmap_size); //ntfs_bitmap = (unsigned char*)calloc(sizeof(unsigned char), bitmap_size); if ((bitmap == NULL) || (ntfs_bitmap == NULL)) { log_mesg(0, 1, 1, fs_opt.debug, "%s: bitmap alloc error\n", __FILE__); } memset(ntfs_bitmap, 0, bitmap_size); pos = 0; used_block = 0; free_block = 0; count = ntfs_attr_pread(ntfs->lcnbmp_na, pos, bitmap_size, ntfs_bitmap); /// init progress progress_bar prog; progress_init(&prog, start, image_hdr.totalblock, image_hdr.totalblock, BITMAP, bit_size); if (count == -1){ // On error and nothing has been read log_mesg(0, 1, 1, fs_opt.debug, "%s: read ntfs attr error: %s\n", __FILE__, strerror(errno)); } if (count != bitmap_size){ log_mesg(0, 1, 1, fs_opt.debug, "%s: the readed size of ntfs_attr not expected: %s\n", __FILE__, strerror(errno)); } for (current_block = 0; current_block < ntfs->nr_clusters; current_block++) { char bit; bit = ntfs_bit_get(ntfs_bitmap, current_block); if (bit == -1){ // Return -1 on error log_mesg(0, 1, 1, fs_opt.debug, "%s: check bitmap error\n", __FILE__); }else if(bit == 1){ // The value of the bit (0 or 1) pc_set_bit(current_block, bitmap); used_block++; } else { pc_clear_bit(current_block, bitmap); free_block++; } /// update progress update_pui(&prog, current_block, current_block, 0); } /// update progress update_pui(&prog, 1, 1, 1); log_mesg(3, 0, 0, fs_opt.debug, "%s: [bitmap] Used Block\t: %llu\n", __FILE__, used_block); log_mesg(3, 0, 0, fs_opt.debug, "%s: [bitmap] Free Block\t: %llu\n", __FILE__, free_block); log_mesg(3, 0, 0, fs_opt.debug, "%s: [bitmap] Calculated Bitmap Size\t: %lu\n", __FILE__, bitmap_size); log_mesg(3, 0, 0, fs_opt.debug, "%s: [bitmap] Bitmap attribute data size\t: %"PRId64"\n", __FILE__, ntfs->lcnbmp_na->data_size); log_mesg(3, 0, 0, fs_opt.debug, "%s: [bitmap] Bitmap attribute initialized size\t: %"PRId64"\n", __FILE__, ntfs->lcnbmp_na->initialized_size); log_mesg(3, 0, 0, fs_opt.debug, "%s: [bitmap] Bitmap attribute allocated size\t: %"PRId64"\n", __FILE__, ntfs->lcnbmp_na->allocated_size); free(ntfs_bitmap); log_mesg(3, 0, 0, fs_opt.debug, "%s: bitmap alloc free\n", __FILE__); fs_close(); log_mesg(3, 0, 0, fs_opt.debug, "%s: fs_close done\n", __FILE__); if (used_block != image_hdr.usedblocks) { log_mesg(0, 1, 1, fs_opt.debug, "%s: used blocks count mismatch: %llu in header, %llu from readbitmap\n", __FILE__, image_hdr.usedblocks, used_block); } } /// read super block and write to image head extern void initial_image_hdr(char* device, image_head* image_hdr) { fs_open(device); strncpy(image_hdr->magic, IMAGE_MAGIC, IMAGE_MAGIC_SIZE); strncpy(image_hdr->fs, ntfs_MAGIC, FS_MAGIC_SIZE); image_hdr->block_size = (int)ntfs->cluster_size; image_hdr->totalblock = (unsigned long long)ntfs->nr_clusters; #ifdef NTFS3G log_mesg(3, 0, 0, fs_opt.debug, "%s: ntfs - nr_free:\t: %"PRId64"\n", __FILE__, ntfs->free_clusters); image_hdr->usedblocks = (unsigned long long)(ntfs->nr_clusters - ntfs->free_clusters); #else log_mesg(3, 0, 0, fs_opt.debug, "%s: ntfs - nr_free:\t: %ld\n", __FILE__, ntfs->nr_free_clusters); image_hdr->usedblocks = (unsigned long long)(ntfs->nr_clusters - ntfs->nr_free_clusters); #endif image_hdr->device_size = (unsigned long long)ntfs_device_size_get(ntfs->dev, 1); fs_close(); log_mesg(3, 0, 0, fs_opt.debug, "%s: hdr - usedblocks:\t: %llu\n", __FILE__, image_hdr->usedblocks); log_mesg(3, 0, 0, fs_opt.debug, "%s: hdr - totalblocks:\t: %llu\n", __FILE__, image_hdr->totalblock); } partclone-0.2.86/src/ntfsclone-ng.h000066400000000000000000000012041262102574200171310ustar00rootroot00000000000000/** * ntfsclone.h - part of Partclone project * * Copyright (c) 2007~ Thomas Tsai * * read ntfs super block and bitmap * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ /// readbitmap - read bitmap extern void readbitmap(char* device, image_head image_hdr, unsigned long* bitmap, int pui); /// read super block and write to image head extern void initial_image_hdr(char* device, image_head* image_hdr); partclone-0.2.86/src/ntfsfixboot.c000066400000000000000000000257401262102574200171070ustar00rootroot00000000000000/* ntfsfixboot - deals with braindeadness with moving NTFS filesystems. version 1.0 Copyright (C) 2009 Orgad Shaneh Loosely based on the work of Daniel J. Grace (2006) This program modifies the geometry settings on an NTFS partition as described in . It is needed for booting, as described in libntfs It will NOT work for Windows NT v3.5 and below. It is designed for NT4/2000/XP and later versions. Like any other program that tinkers with the contents of your HD, this program may cause data corruption. USE AT YOUR OWN RISK. You have been warned. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #define _LARGEFILE64_SOURCE #include #include #include #include #include #include #include #include #include #include int flip(void *p, int size) { uint16_t test; int iter; char *c; char t; if (size % 2) return 1; // Determine system architecture test = 1; c = (char *)&test; if (*c) return 0; // reverse bytes c = p; for (iter = 0 ; iter < size / 2; ++iter) { t = c[iter]; c[iter] = c[size-iter-1]; c[size-iter-1] = t; } return 0; } int usage(char *progname) { fprintf(stderr, "adjust filesystem geometry for a NTFS partition" "\nUsage: %s [-h # -t #] [-s start] [-b] [-w] [-f] [-p] device" "\nwhere device points to an NTFS partition" "\n" "\nOptions:" "\n-w:\t\tWrite new start sector to the partition." "\n-h # -t #:\tSpecify number of heads and number of sectors per track" "\n\t\tIf omitted, determined via ioctl." "\n-s start:\tNew start sector to write." "\n\t\tIf omitted, determined via ioctl." "\n-b:\t\tProceed even if the specified device is not a" "\n\t\tpartition (e.g. a regular file)" "\n-f:\t\tForce the operation to occur even if device does not look" "\n\t\tlike a valid NTFS partition or values are equal." "\n-p:\t\tPrint debug information (values read, values requested etc.)" "\n" "\nThis utility displays the current starting sector as defined by the" "\nthe filesystem. No change will actually be made without the -w" "\noption." "\n" "\nExit status:" "\n* 0 - success (values are correct, or changed successfully)" "\n* 1 - a change is needed, but -w was not specified" "\n* 2 - an error occured" "\n", progname ); return 0; } struct ntfs_geometry { uint16_t sectors; uint16_t heads; uint32_t start; } __attribute__((packed)); void flip_all(struct ntfs_geometry *geo) { flip(&geo->heads, 2); flip(&geo->sectors, 2); flip(&geo->start, 4); } char optSpecifyStart = 0, optSpecifyHS = 0, optWrite = 0, optBlock = 0, optForce = 0, optPrint = 0; char *optDeviceName = NULL; struct ntfs_geometry opt_geom = {0, 0, 0}; void print(const char *s, ...) { va_list ap; if (optPrint) { va_start(ap, s); vprintf(s, ap); va_end(ap); } } int read_options(int argc, char *argv[]) { int i; char opt; int readopts = 1; if (argc <= 1) { usage(argv[0]); return 2; } // read options for (i = 1 ; i < argc ; ++i) { if (argv[i][0] == '-' && readopts) { opt = argv[i][1]; // -h, -t and -s need a number to follow if ((opt == 'h') || (opt == 't') || (opt == 's')) { char *sizePtr, *endPtr; if (argv[i][2]) { sizePtr = &argv[i][2]; } else if (i+1 < argc) { sizePtr = argv[++i]; } else { fprintf(stderr, "ERROR: Size must be specified for option -%c\n", opt); usage(argv[0]); return 1; } switch (opt) { case 'h': optSpecifyHS = 1; opt_geom.heads = strtoul(sizePtr, &endPtr, 10); break; case 't': optSpecifyHS = 1; opt_geom.sectors = strtoul(sizePtr, &endPtr, 10); break; case 's': optSpecifyStart = 1; opt_geom.start = strtoul(sizePtr, &endPtr, 10); break; } // assert the value is a number if (endPtr == sizePtr || *endPtr) { fprintf(stderr, "ERROR: Invalid size specified for option -%c\n", opt); usage(argv[0]); return 1; } continue; } if (opt && argv[i][2]) { fprintf(stderr, "Unknown option '%s'\n", argv[i]); usage(argv[0]); return 1; } switch (opt) { case '-': readopts = 0; break; case 'b': optBlock = 1; break; case 'w': optWrite = 1; break; case 'f': optForce = 1; break; case 'p': optPrint = 1; break; default: fprintf(stderr, "Unknown option '%s'\n", argv[i]); usage(argv[0]); return 1; } continue; } // If we reach here, we're reading a device name if (optDeviceName) { fprintf(stderr, "Only one device may be specified\n"); usage(argv[0]); return 1; } optDeviceName = argv[i]; } if (!optDeviceName) { fprintf(stderr, "No device name specified\n"); usage(argv[0]); return 1; } return 0; } int main(int argc, char *argv[]) { int device = 0; int opt_res; char haveGeom = 0; uint16_t sector_size = 0; uint64_t total_sectors = 0; off64_t last_sector = 0; struct hd_geometry part_geom = {0, 0, 0, 0}; struct ntfs_geometry fs_geom = {0, 0, 0}; struct ntfs_geometry bak_geom = {0, 0, 0}; struct ntfs_geometry set_geom = {0, 0, 0}; char br_sector[512]; char bak_sector[512]; const int geomsize = sizeof(struct ntfs_geometry); puts("ntfsfixboot version 1.0"); // read program options (into global variables) opt_res = read_options(argc, argv); if (opt_res) return opt_res; // verify that we can open the device in readonly mode if ((device = open(optDeviceName, (optWrite ? O_RDWR : O_RDONLY) | O_SYNC)) < 0) { perror("open"); return 2; } // check to see if it's a partition, and determine geometry if (ioctl(device, HDIO_GETGEO, &part_geom)) { if (!optBlock) { fprintf(stderr, "Failed to read disk geometry. Perhaps this is not a partition?\n"); fprintf(stderr, "Verify that you are using the correct device or use the -b option.\n"); fprintf(stderr, "The exact error was:\n"); perror("ioctl"); return 2; } else if (!optSpecifyStart && optWrite) { fprintf(stderr, "Failed to read disk geometry, and -s option was not specified.\n"); fprintf(stderr, "No update can be made without this information.\n"); fprintf(stderr, "The exact error was:\n"); perror("ioctl"); return 2; } } else { haveGeom = 1; if (!optForce && !part_geom.start) { fprintf(stderr, "This looks like an entire disk (start=0) instead of a single partition.\n"); fprintf(stderr, "It will not be modified without the -f (force) option.\n"); if (optWrite) { return 2; } } } if (read(device, br_sector, 512) != 512) { fprintf(stderr, "Error reading device!"); perror("read"); } // verify that it is an NTFS partition // read "NTFS" magic, or at least what should be if (memcmp(br_sector + 0x03, "NTFS", 4)) { if (!optForce) { fprintf(stderr, "This device does not appear to be a real NTFS volume.\n"); if (!optWrite) { return 2; } } } // filesystem geometry memcpy(&fs_geom, br_sector + 0x18, geomsize); flip_all(&fs_geom); // backup sector memcpy(§or_size, br_sector + 0x0b, 2); memcpy(&total_sectors, br_sector + 0x28, 8); flip(§or_size, 2); flip(&total_sectors, 8); last_sector = total_sectors * sector_size; // very unlikely to happen... if (sector_size != 512) { fprintf(stderr, "Sector size is not 512. this mode is not supported!"); return 2; } if (last_sector == 0) { fprintf(stderr, "Unable to determine last (backup) sector!\n"); return 2; } if (lseek64(device, last_sector, SEEK_SET) < 0) { perror("lseek64"); return 2; } if (read(device, &bak_sector, 512) != 512) { fprintf(stderr, "Unable to read backup sector.\n"); return 2; } memcpy(&bak_geom, bak_sector + 0x18, geomsize); flip_all(&bak_geom); if (optSpecifyHS) { if (!opt_geom.heads || !opt_geom.sectors) { fprintf(stderr, "Must specify both heads and sectors per track or none!\n"); return 2; } } // behavior description follows. HS and Start values indicates SpecifyHS and SpecifyStart // part: use partition value // fs : use filesystem value (don't change anything) // opt : use user value // HS Start tgt HS tgt Start // 0 0 part part (if no partition geometry, use fs) // 0 1 fs opt // 1 0 opt part // 1 1 opt opt if (!optSpecifyHS && !optSpecifyStart) { if (haveGeom) { set_geom.heads = part_geom.heads; set_geom.sectors = part_geom.sectors; set_geom.start = part_geom.start; } else { set_geom = fs_geom; } } else { set_geom = opt_geom; if (!optSpecifyStart) { set_geom.start = part_geom.start; } if (!optSpecifyHS) { set_geom.heads = fs_geom.heads; set_geom.sectors = fs_geom.sectors; } } // print all details print("\t\tHeads\tSectors\tStart\n"); if (haveGeom) { print("partition:\t%d\t%d\t%lu\n", part_geom.heads, part_geom.sectors, part_geom.start); } print("filesystem:\t%d\t%d\t%lu\n", fs_geom.heads, fs_geom.sectors, fs_geom.start); print("backup sector\t%d\t%d\t%lu\n", bak_geom.heads, bak_geom.sectors, bak_geom.start); print("target:\t\t%d\t%d\t%lu\n", set_geom.heads, set_geom.sectors, set_geom.start); if (!memcmp(&set_geom, &fs_geom, geomsize) && !memcmp(&set_geom, &bak_geom, geomsize) && !optForce && !memcmp(br_sector, bak_sector, 512)) { puts("No changes neccessary."); return 0; } if (!optWrite) { puts("Changes will be written to disk only with -w flag"); return 1; } flip_all(&set_geom); memcpy(br_sector + 0x18, &set_geom, geomsize); // write back changes if (lseek(device, 0L, SEEK_SET) < 0) { perror("lseek"); return 2; } if (write(device, br_sector, 512) != 512) { perror("write"); return 2; } // write to backup sector if (lseek64(device, last_sector, SEEK_SET) < 0) { perror("lseek64"); return 2; } if (write(device, br_sector, 512) != 512) { perror("write"); return 2; } if (fsync(device)) { perror("fsync"); return 2; } if (close(device)) { perror("close"); return 2; } puts("done!"); return 0; } partclone-0.2.86/src/partclone.c000066400000000000000000000751441262102574200165340ustar00rootroot00000000000000/** * partclone.c - Part of Partclone project. * * Copyright (c) 2007~ Thomas Tsai * * more functions used by main. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ #include #define _LARGEFILE64_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "gettext.h" #include #define _(STRING) gettext(STRING) //#define PACKAGE "partclone" #include "version.h" #include "partclone.h" #if defined(linux) && defined(_IO) && !defined(BLKGETSIZE) #define BLKGETSIZE _IO(0x12,96) /* Get device size in 512-byte blocks. */ #endif #if defined(linux) && defined(_IOR) && !defined(BLKGETSIZE64) #define BLKGETSIZE64 _IOR(0x12,114,size_t) /* Get device size in bytes. */ #endif FILE* msg = NULL; #ifdef HAVE_LIBNCURSESW #include WINDOW *log_win; WINDOW *p_win; WINDOW *box_win; WINDOW *bar_win; WINDOW *tbar_win; WINDOW *ptclscr_win; SCREEN *ptclscr; int log_y_line = 0; #endif void print_readable_size_str(unsigned long long size_byte, char *new_size_str) { float new_size = 1.0; memset(new_size_str, 0, 11); uint64_t tbyte=1000000000000.0; uint64_t gbyte=1000000000; uint64_t mbyte=1000000; uint64_t kbyte=1000; if (size_byte == 0) snprintf(new_size_str, 11, "%llu", size_byte); if (size_byte >= tbyte) { new_size = (float)size_byte / (float)tbyte; snprintf(new_size_str, 11, "%5.1f TB", new_size); } else if (size_byte >= gbyte) { new_size = (float)size_byte / (float)gbyte; snprintf(new_size_str, 11, "%5.1f GB", new_size); } else if (size_byte >= mbyte) { new_size = (float)size_byte / (float)mbyte; snprintf(new_size_str, 11, "%5.1f MB", new_size); } else if (size_byte >= kbyte) { new_size = (float)size_byte / (float)kbyte; snprintf(new_size_str, 11, "%5.1f KB", new_size); } else { snprintf(new_size_str, 11, "%3i Byte", (int)size_byte); } } /** * options * usage - print message "how to use this" * print_version * parse_options - get parameters from agrc, argv */ void usage(void) { fprintf(stderr, "%s v%s http://partclone.org\nUsage: %s [OPTIONS]\n" #ifdef CHKIMG " Check partclone image.\n" #else #ifdef RESTORE " Restore partclone image to a device or standard output.\n" #else " Efficiently clone to an image, device or standard output.\n" #endif #endif "\n" #ifndef CHKIMG " -o, --output FILE Output FILE\n" " -O --overwrite FILE Output FILE, overwriting if exists\n" " -W --restore_raw_file create special raw file for loop device\n" #endif " -s, --source FILE Source FILE\n" " -L, --logfile FILE Log FILE\n" #ifndef CHKIMG #ifndef RESTORE #ifndef DD " -c, --clone Save to the special image format\n" " -r, --restore Restore from the special image format\n" " -b, --dev-to-dev Local device to device copy mode\n" #endif " -D, --domain Create ddrescue domain log from source device\n" " --offset_domain=X Add offset X (bytes) to domain log values\n" " -R, --rescue Continue clone while disk read errors\n" #endif " -w, --skip_write_error Continue restore while write errors\n" #endif " -dX, --debug=X Set the debug level to X = [0|1|2]\n" " -C, --no_check Don't check device size and free space\n" #ifdef HAVE_LIBNCURSESW " -N, --ncurses Using Ncurses User Interface\n" #endif #ifndef CHKIMG " -I, --ignore_fschk Ignore filesystem check\n" #endif " -i, --ignore_crc Ignore crc check error\n" " -F, --force Force progress\n" " -f, --UI-fresh Fresh times of progress\n" " -B, --no_block_detail Show progress message without block detail\n" " -z, --buffer_size SIZE Read/write buffer size (default: %d)\n" #ifndef CHKIMG " -q, --quiet Disable progress message\n" " -E, --offset=X Add offset X (bytes) to OUTPUT\n" #endif " -n, --note NOTE Display Message Note (128 words)\n" " -v, --version Display partclone version\n" " -h, --help Display this help\n" , EXECNAME, VERSION, EXECNAME, DEFAULT_BUFFER_SIZE); exit(0); } void print_version(void){ printf("Partclone : v%s (%s) \n", VERSION, git_version); exit(0); } enum { OPT_OFFSET_DOMAIN = 1000 }; void parse_options(int argc, char **argv, cmd_opt* opt) { #ifdef CHKIMG static const char *sopt = "-hvd::L:s:f:CFiBz:Nn:"; #else #ifdef RESTORE static const char *sopt = "-hvd::L:o:O:s:f:CFINiqWBz:E:n:"; #elif DD static const char *sopt = "-hvd::L:o:O:s:f:CFINiqWBz:E:n:"; #else static const char *sopt = "-hvd::L:cbrDo:O:s:f:RCFINiqWBz:E:n:"; #endif #endif static const struct option lopt[] = { // common options { "help", no_argument, NULL, 'h' }, { "print_version", no_argument, NULL, 'v' }, { "note", required_argument, NULL, 'n' }, { "source", required_argument, NULL, 's' }, { "debug", optional_argument, NULL, 'd' }, { "logfile", required_argument, NULL, 'L' }, { "UI-fresh", required_argument, NULL, 'f' }, { "no_check", no_argument, NULL, 'C' }, { "ignore_crc", no_argument, NULL, 'i' }, { "force", no_argument, NULL, 'F' }, { "no_block_detail", no_argument, NULL, 'B' }, { "buffer_size", required_argument, NULL, 'z' }, // not RESTORE and not CHKIMG #ifndef CHKIMG #ifndef RESTORE #ifndef DD { "clone", no_argument, NULL, 'c' }, { "restore", no_argument, NULL, 'r' }, { "dev-to-dev", no_argument, NULL, 'b' }, #endif { "domain", no_argument, NULL, 'D' }, { "offset_domain", required_argument, NULL, OPT_OFFSET_DOMAIN }, { "rescue", no_argument, NULL, 'R' }, #endif #endif // not CHKIMG #ifndef CHKIMG { "output", required_argument, NULL, 'o' }, { "overwrite", required_argument, NULL, 'O' }, { "restore_raw_file", no_argument, NULL, 'W' }, { "skip_write_error", no_argument, NULL, 'w' }, { "ignore_fschk", no_argument, NULL, 'I' }, { "quiet", no_argument, NULL, 'q' }, { "offset", required_argument, NULL, 'E' }, #endif #ifdef HAVE_LIBNCURSESW { "ncurses", no_argument, NULL, 'N' }, #endif { NULL, 0, NULL, 0 } }; int c; int mode = 0; memset(opt, 0, sizeof(cmd_opt)); opt->debug = 0; opt->offset = 0; opt->rescue = 0; opt->skip_write_error = 0; opt->check = 1; opt->ignore_crc = 0; opt->quiet = 0; opt->no_block_detail = 0; opt->fresh = 2; opt->logfile = "/var/log/partclone.log"; opt->buffer_size = DEFAULT_BUFFER_SIZE; #ifdef DD #ifndef RESTORE #ifndef CHKIMG opt->ddd++; mode=1; #endif #endif #endif #ifdef RESTORE opt->restore++; mode=1; #endif #ifdef CHKIMG opt->restore++; opt->chkimg++; mode=1; #endif while ((c = getopt_long(argc, argv, sopt, lopt, NULL)) != -1) { switch (c) { case 'h': case '?': usage(); break; case 'v': print_version(); break; case 'n': strncpy(opt->note, optarg, NOTE_SIZE); break; case 's': opt->source = optarg; break; case 'd': if (optarg) opt->debug = atol(optarg); else opt->debug = 1; break; case 'L': opt->logfile = optarg; break; case 'f': opt->fresh = atol(optarg); break; case 'C': opt->check = 0; break; case 'i': opt->ignore_crc = 1; break; case 'F': opt->force++; break; case 'B': opt->no_block_detail = 1; break; case 'z': opt->buffer_size = atol(optarg); break; #ifndef CHKIMG #ifndef RESTORE #ifndef DD case 'c': opt->clone++; mode=1; break; case 'r': opt->restore++; mode=1; break; case 'b': opt->dd++; mode=1; break; #endif case 'D': opt->domain++; mode=1; break; case OPT_OFFSET_DOMAIN: opt->offset_domain = strtoull(optarg, NULL, 0); break; case 'R': opt->rescue++; break; #endif #endif #ifndef CHKIMG case 'O': opt->overwrite++; case 'o': opt->target = optarg; break; case 'W': opt->restore_raw_file = 1; break; case 'w': opt->skip_write_error = 1; break; case 'I': opt->ignore_fschk++; break; case 'q': opt->quiet = 1; break; case 'E': opt->offset = atol(optarg); break; #endif #ifdef HAVE_LIBNCURSESW case 'N': opt->ncurses = 1; break; #endif default: fprintf(stderr, "Unknown option '%s'.\n", argv[optind-1]); usage(); } } if (mode != 1) { usage(); } if (!opt->debug) { opt->debug = 0; } if ((!opt->target) && (!opt->source)) { fprintf(stderr, "There is no image name. Use --help get more info.\n"); exit(0); } if (opt->buffer_size < 512) { fprintf(stderr, "Too small or bad buffer size. Use --help get more info.\n"); exit(0); } if (!opt->target) opt->target = "-"; if (!opt->source) opt->source = "-"; if (opt->clone || opt->domain) { if ((!strcmp(opt->source, "-")) || (!opt->source)) { fprintf(stderr, "Partclone can't %s from stdin.\nFor help, type: %s -h\n", opt->clone ? "clone" : "make domain log", EXECNAME); exit(0); } } #ifndef CHKIMG if (opt->restore) { if ((!strcmp(opt->target, "-")) || (!opt->target)) { fprintf(stderr, "Partclone can't restore to stdout.\nFor help,type: %s -h\n", EXECNAME); exit(0); } } #endif } /** * Ncurses Text User Interface * open_ncurses - open text window * close_ncurses - close text window */ int open_ncurses() { #ifdef HAVE_LIBNCURSESW int debug = 1; FILE *in = fopen( "/dev/stderr", "r" ); FILE *out = fopen( "/dev/stderr", "w" ); int terminal_x = 0; int terminal_y = 0; ptclscr = newterm(NULL, out, in); refresh(); if (!ptclscr) log_mesg(0, 1, 1, debug, "partclone ncurses initial error\n"); if (!set_term(ptclscr)) log_mesg(0, 1, 1, debug, "partclone ncurses set term error\n"); ptclscr_win = newwin(LINES, COLS, 0, 0); // check terminal width and height getmaxyx(ptclscr_win, terminal_y, terminal_x); // set window position int log_line = 12; int log_row = 60; int log_y_pos = (terminal_y-24)/2+2; int log_x_pos = (terminal_x-log_row)/2; int gap = 0; int p_line = 8; int p_row = log_row; int p_y_pos = log_y_pos+log_line+gap; int p_x_pos = log_x_pos; int size_ok = 1; if (terminal_y < (log_line+gap+p_line+3)) size_ok = 0; if (terminal_x < (log_row+2)) size_ok = 0; if (size_ok == 0) { log_mesg(0, 0, 0, debug, "Terminal width(%i) or height(%i) too small\n", terminal_x, terminal_y); return 0; } /// check color pair if (!has_colors()) { log_mesg(0, 0, 0, debug, "Terminal color error\n"); return 0; } if (start_color() != OK){ log_mesg(0, 0, 0, debug, "Terminal can't start color mode\n"); return 0; } /// define color init_pair(1, COLOR_WHITE, COLOR_BLUE); ///stdscr init_pair(2, COLOR_RED, COLOR_WHITE); ///sub window init_pair(3, COLOR_BLUE, COLOR_WHITE); ///sub window /// write background color bkgd(COLOR_PAIR(1)); wbkgd(ptclscr_win,COLOR_PAIR(2)); touchwin(ptclscr_win); refresh(); /// init main box attrset(COLOR_PAIR(2)); box_win = subwin(ptclscr_win, (log_line+gap+p_line+2), log_row+2, log_y_pos-1, log_x_pos-1); box(box_win, ACS_VLINE, ACS_HLINE); wrefresh(box_win); wbkgd(box_win, COLOR_PAIR(2)); mvprintw((log_y_pos-1), ((terminal_x-9)/2), " Partclone "); attroff(COLOR_PAIR(2)); attrset(COLOR_PAIR(3)); /// init log window log_win = subwin(ptclscr_win, log_line, log_row, log_y_pos, log_x_pos); wbkgd(log_win, COLOR_PAIR(3)); touchwin(log_win); refresh(); // init progress window p_win = subwin(ptclscr_win, p_line, p_row, p_y_pos, p_x_pos); wbkgd(p_win, COLOR_PAIR(3)); touchwin(p_win); refresh(); // init progress window bar_win = subwin(ptclscr_win, 1, p_row-10, p_y_pos+4, p_x_pos); wbkgd(bar_win, COLOR_PAIR(1)); touchwin(bar_win); refresh(); // init total block progress window tbar_win = subwin(ptclscr_win, 1, p_row-10, p_y_pos+7, p_x_pos); wbkgd(tbar_win, COLOR_PAIR(1)); touchwin(tbar_win); refresh(); scrollok(log_win, TRUE); if (touchwin(ptclscr_win) == ERR) return 0; refresh(); #endif return 1; } void close_ncurses() { #ifdef HAVE_LIBNCURSESW sleep(3); attroff(COLOR_PAIR(3)); delwin(log_win); delwin(p_win); delwin(bar_win); delwin(box_win); touchwin(ptclscr_win); endwin(); delscreen (ptclscr); #endif } /** * debug message * open_log - to open file default is /var/log/partclone.log * log_mesg - write log to the file * - write log and exit * - write to stderr... * close_log - to close file /var/log/partclone.log */ void open_log(char* source) { msg = fopen(source,"w"); if (msg == NULL) { fprintf(stderr, "open logfile %s error\n", source); exit(0); } } void log_mesg(int log_level, int log_exit, int log_stderr, int debug, const char *fmt, ...) { va_list args; extern cmd_opt opt; char tmp_str[512]; if (log_level > debug && (!log_exit || opt.force)) return; va_start(args, fmt); vsnprintf(tmp_str, sizeof(tmp_str), fmt, args); va_end(args); if (opt.ncurses) { #ifdef HAVE_LIBNCURSESW setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); if ((log_stderr) && (log_level <= debug)) { if (log_exit) wattron(log_win, A_STANDOUT); wprintw(log_win, tmp_str); if (log_exit) { wattroff(log_win, A_STANDOUT); sleep(3); } wrefresh(log_win); log_y_line++; } #endif } else { /// write log to stderr if log_stderr is true if ((log_stderr == 1) && (log_level <= debug)) fprintf(stderr, "%s", tmp_str); } /// write log to logfile if debug is true if (log_level <= debug) fprintf(msg, "%s", tmp_str); /// clear message fflush(msg); /// exit if lexit true if ((!opt.force) && log_exit) { close_ncurses(); fprintf(stderr, "Partclone fail, please check %s !\n", opt.logfile); exit(1); } } void close_log(void) { fclose(msg); } /// get image_head from image file void restore_image_hdr(int* ret, cmd_opt* opt, image_head* image_hdr) { int r_size; char* buffer; unsigned long long dev_size; int debug = opt->debug; buffer = (char*)malloc(sizeof(image_head)); if (buffer == NULL) log_mesg(0, 1, 1, debug, "%s, %i, not enough memory\n", __func__, __LINE__); memset(buffer, 0, sizeof(image_head)); r_size = read_all(ret, buffer, sizeof(image_head), opt); if (r_size == -1) log_mesg(0, 1, 1, debug, "read image_hdr error\n"); memcpy(image_hdr, buffer, sizeof(image_head)); free(buffer); dev_size = (unsigned long long)(image_hdr->totalblock * image_hdr->block_size); if (image_hdr->device_size != dev_size) image_hdr->device_size = dev_size; } /// get partition size unsigned long long get_partition_size(int* ret) { unsigned long long dest_size = 0; unsigned long dest_block; struct stat stat; int debug = 1; if (!fstat(*ret, &stat)) { if (S_ISFIFO(stat.st_mode)) { dest_size = 0; } else if (S_ISREG(stat.st_mode)) { dest_size = stat.st_size; } else { #ifdef BLKGETSIZE64 if (ioctl(*ret, BLKGETSIZE64, &dest_size) < 0) log_mesg(0, 0, 0, debug, "get device size error, Use option -C to disable size checking(Dangerous).\n"); log_mesg(1, 0, 0, debug, "get device size %llu by ioctl BLKGETSIZE64,\n", dest_size); return dest_size; #endif #ifdef BLKGETSIZE if (ioctl(*ret, BLKGETSIZE, &dest_block) >= 0) dest_size = (unsigned long long)(dest_block * 512); log_mesg(1, 0, 0, debug, "get block %lu and device size %llu by ioctl BLKGETSIZE,\n", dest_block, dest_size); return dest_size; #endif } } else { log_mesg(0, 0, 0, debug, "fstat size error, Use option -C to disable size checking(Dangerous).\n"); } return dest_size; } /// check partition size int check_size(int* ret, unsigned long long size) { unsigned long long dest_size; int debug = 1; dest_size = get_partition_size(ret); if (dest_size < size){ log_mesg(0, 1, 1, debug, "Target partition size(%llu MB) is smaller than source(%llu MB). Use option -C to disable size checking(Dangerous).\n", print_size(dest_size, MBYTE), print_size(size, MBYTE)); return 1; } return 0; } /// check free space void check_free_space(int* ret, unsigned long long size) { unsigned long long dest_size; struct statvfs stvfs; struct stat stat; int debug = 1; if (fstatvfs(*ret, &stvfs) == -1) { printf("WARNING: Unknown free space on the destination: %s\n", strerror(errno)); return; } /* if file is a FIFO there is no point in checking the size */ if (!fstat(*ret, &stat)) { if (S_ISFIFO(stat.st_mode)) return; } else { printf("WARNING: Couldn't get file info because of the following error: %s\n", strerror(errno)); } dest_size = (unsigned long long)stvfs.f_frsize * stvfs.f_bfree; if (!dest_size) dest_size = (unsigned long long)stvfs.f_bsize * stvfs.f_bfree; if (dest_size < size) log_mesg(0, 1, 1, debug, "Destination doesn't have enough free space: %llu MB < %llu MB\n", print_size(dest_size, MBYTE), print_size(size, MBYTE)); } /// check free memory size int check_mem_size(image_head image_hdr, cmd_opt opt, unsigned long long *mem_size) { unsigned long long image_head_size = 0; unsigned long long bitmap_size = 0; int crc_io_size = 0; void *test_mem; image_head_size = sizeof(image_head); bitmap_size = sizeof(unsigned long)*LONGS(image_hdr.totalblock); crc_io_size = CRC_SIZE+image_hdr.block_size; *mem_size = image_head_size + bitmap_size + crc_io_size; log_mesg(0, 0, 0, 1, "we need memory: %llu bytes\nimage head %llu, bitmap %llu, crc %i bytes\n", *mem_size, image_head_size, bitmap_size, crc_io_size); test_mem = malloc(*mem_size); if (test_mem == NULL){ free(test_mem); return -1; } else { free(test_mem); } return 1; } /// get bitmap from image file to restore data void get_image_bitmap(int* ret, cmd_opt opt, image_head image_hdr, unsigned long* bitmap) { unsigned long long size, r_size, r_need; char buffer[16384]; unsigned long long offset = 0; unsigned long long bused = 0, bfree = 0; int i, debug = opt.debug; int err_exit = 1; size = sizeof(char)*image_hdr.totalblock; while (size > 0) { r_need = size > sizeof(buffer) ? sizeof(buffer) : size; r_size = read_all(ret, buffer, r_need, &opt); if (r_size < r_need) log_mesg(0, 1, 1, debug, "Unable to read bitmap.\n"); for (i = 0; i < r_need; i++) { if (buffer[i] == 1) { pc_set_bit(offset + i, bitmap); bused++; } else { pc_clear_bit(offset + i, bitmap); bfree++; } } offset += r_need; size -= r_need; } if (debug >= 2) { if (image_hdr.usedblocks != bused) { if (opt.force) err_exit = 0; else err_exit = 1; log_mesg(0, err_exit, 1, debug, "The Used Block count is different. (bitmap %llu != image_head %llu)\n" "Try to use --force to skip the metadata error.\n", bused, image_hdr.usedblocks); } } } /** * for open and close * open_source - open device or image or stdin * open_target - open device or image or stdout * * the data string * clone: read from device to image/stdout * restore: read from image/stdin to device * dd: read from device to device !! not complete * */ int check_mount(const char* device, char* mount_p){ char *real_file = NULL, *real_fsname = NULL; FILE * f; struct mntent * mnt; int isMounted = 0; real_file = malloc(PATH_MAX + 1); if (!real_file) { return -1; } real_fsname = malloc(PATH_MAX + 1); if (!real_fsname) { free(real_file); return -1; } if (!realpath(device, real_file)) return -1; if ((f = setmntent(MOUNTED, "r")) == 0) { free(real_file); free(real_fsname); return -1; } while ((mnt = getmntent (f)) != 0) { if (!realpath(mnt->mnt_fsname, real_fsname)) continue; if (strcmp(real_file, real_fsname) == 0) { isMounted = 1; strcpy(mount_p, mnt->mnt_dir); } } endmntent(f); free(real_file); free(real_fsname); return isMounted; } int open_source(char* source, cmd_opt* opt) { int ret = 0; int debug = opt->debug; char *mp; int flags = O_RDONLY | O_LARGEFILE; struct stat st_dev; int ddd_block_device = -1; log_mesg(1, 0, 0, debug, "open source file/device %s\n", source); if (opt->ddd) { if (stat(source, &st_dev) != -1) { if (S_ISBLK(st_dev.st_mode)) ddd_block_device = 1; else ddd_block_device = 0; }else{ ddd_block_device = 0; } log_mesg(1, 0, 0, debug, "ddd source file(0) or device(1) ? %i \n", ddd_block_device); } if ((opt->clone) || (opt->dd) || (opt->domain) || (ddd_block_device == 1)) { /// always is device, clone from device=source mp = malloc(PATH_MAX + 1); if (!mp) log_mesg(0, 1, 1, debug, "%s, %i, not enough memory\n", __func__, __LINE__); if (check_mount(source, mp) == 1) { log_mesg(0, 0, 1, debug, "device (%s) is mounted at %s\n", source, mp); free(mp); log_mesg(0, 1, 1, debug, "error exit\n"); } free(mp); if ((ret = open(source, flags, S_IRUSR)) == -1) log_mesg(0, 1, 1, debug, "clone: open %s error\n", source); } else if ((opt->restore) || (ddd_block_device == 0)) { if (strcmp(source, "-") == 0) { if ((ret = fileno(stdin)) == -1) log_mesg(0, 1, 1, debug, "restore: open %s(stdin) error\n", source); } else { if ((ret = open (source, flags, S_IRWXU)) == -1) log_mesg(0, 1, 1, debug, "restore: open %s error\n", source); } } return ret; } int open_target(char* target, cmd_opt* opt) { int ret = 0; int debug = opt->debug; char *mp; int flags = O_WRONLY | O_LARGEFILE; struct stat st_dev; int ddd_block_device = -1; log_mesg(1, 0, 0, debug, "open target file/device %s\n", target); if (opt->ddd) { if (stat(target, &st_dev) != -1) { if (S_ISBLK(st_dev.st_mode)) ddd_block_device = 1; else ddd_block_device = 0; } else { ddd_block_device = 0; } log_mesg(1, 0, 0, debug, "ddd target file(0) or device(1) ? %i \n", ddd_block_device); } if (opt->restore_raw_file == 1) { ddd_block_device = 0; } if (opt->clone || opt->domain || (ddd_block_device == 0)) { if (strcmp(target, "-") == 0) { if ((ret = fileno(stdout)) == -1) log_mesg(0, 1, 1, debug, "clone: open %s(stdout) error\n", target); } else { flags |= O_CREAT | O_TRUNC; if (!opt->overwrite) flags |= O_EXCL; if ((ret = open(target, flags, S_IRUSR|S_IWUSR)) == -1) { if (errno == EEXIST) { log_mesg(0, 0, 1, debug, "Output file '%s' already exists.\n" "Use option --overwrite if you want to replace its content.\n", target); } log_mesg(0, 0, 1, debug, "open target fail %s: %s (%i)\n", target, strerror(errno), errno); } } } else if ((opt->restore) || (opt->dd) || (ddd_block_device == 1)) { /// always is device, restore to device=target /// check mounted mp = malloc(PATH_MAX + 1); if (!mp) log_mesg(0, 1, 1, debug, "%s, %i, not enough memory\n", __func__, __LINE__); if (check_mount(target, mp)) { log_mesg(0, 0, 1, debug, "device (%s) is mounted at %s\n", target, mp); free(mp); log_mesg(0, 1, 1, debug, "error exit\n"); } free(mp); /// check block device stat(target, &st_dev); if (!S_ISBLK(st_dev.st_mode)) { log_mesg(1, 0, 1, debug, "Warning, did you restore to non-block device(%s)?\n", target); flags |= O_CREAT; if (!opt->overwrite) flags |= O_EXCL; } if ((ret = open (target, flags, S_IRUSR)) == -1) { if (errno == EEXIST) { log_mesg(0, 0, 1, debug, "Output file '%s' already exists.\n" "Use option --overwrite if you want to replace its content.\n", target); } log_mesg(0, 0, 1, debug, "%s,%s,%i: open %s error(%i)\n", __FILE__, __func__, __LINE__, target, errno); } } return ret; } /// the io function, reference from ntfsprogs(ntfsclone). int io_all(int *fd, char *buf, unsigned long long count, int do_write, cmd_opt* opt) { long long int i; int debug = opt->debug; unsigned long long size = count; extern unsigned long long rescue_write_size; // for sync I/O buffer, when use stdin or pipe. while (count > 0) { if (do_write) i = write(*fd, buf, count); else i = read(*fd, buf, count); if (i < 0) { log_mesg(1, 0, 1, debug, "%s: errno = %i(%s)\n",__func__, errno, strerror(errno)); if (errno != EAGAIN && errno != EINTR) { return -1; } } else if (i == 0) { log_mesg(1, 0, 1, debug, "%s: nothing to read. errno = %i(%s)\n",__func__, errno, strerror(errno)); rescue_write_size = size - count; log_mesg(1, 0, 0, debug, "%s: rescue write size = %llu\n",__func__, rescue_write_size); return 0; } else { count -= i; buf = i + (char *) buf; if (do_write) log_mesg(2, 0, 0, debug, "%s: write ",__func__); else log_mesg(2, 0, 0, debug, "%s: read ",__func__); log_mesg(2, 0, 0, debug, "%lli, %llu left.\n", i, count); } } return size; } void sync_data(int fd, cmd_opt* opt) { log_mesg(0, 0, 1, opt->debug, "Syncing... "); if (fsync(fd) && errno != EINVAL) log_mesg(0, 1, 1, opt->debug, "fsync error: errno = %i\n", errno); log_mesg(0, 0, 1, opt->debug, "OK!\n"); } void rescue_sector(int *fd, unsigned long long pos, char *buff, cmd_opt *opt) { const char badsector_magic[10] = {'B', 'A', 'D', 'S', 'E', 'C', 'T', 'O', 'R', '\0'}; if (lseek(*fd, pos, SEEK_SET) == (off_t)-1) { log_mesg(0, 0, 1, opt->debug, "WARNING: lseek error at %llu\n", pos); memset(buff, '?', PART_SECTOR_SIZE); memcpy(buff, badsector_magic, strlen(badsector_magic)+1); return; } if (io_all(fd, buff, PART_SECTOR_SIZE, 0, opt) == -1) { /// read_all log_mesg(0, 0, 1, opt->debug, "WARNING: Can't read sector at %llu, lost data.\n", pos); memset(buff, '?', PART_SECTOR_SIZE); memcpy(buff, badsector_magic, strlen(badsector_magic)+1); } } /// the crc32 function, reference from libcrc. /// Author is Lammert Bies 1999-2007 /// Mail: info@lammertbies.nl /// http://www.lammertbies.nl/comm/info/nl_crc-calculation.html /// generate crc32 code unsigned long crc32(unsigned long crc, char *buf, int size){ static unsigned long crc_tab32[256]; static int init = 0; unsigned long tmp, long_c; int s = 0; if (init == 0) { /// initial crc table unsigned long init_crc, init_p; int i, j; init_p = 0xEDB88320L; for (i = 0; i < 256; i++) { init_crc = (unsigned long) i; for (j = 0; j < 8; j++) { if ( init_crc & 0x00000001L ) init_crc = ( init_crc >> 1 ) ^ init_p; else init_crc = init_crc >> 1; } crc_tab32[i] = init_crc; } init = 1; } do { /// update crc long_c = 0x000000ffL & (unsigned long) *buf; tmp = crc ^ long_c; crc = (crc >> 8) ^ crc_tab32[ tmp & 0xff ]; } while (++s < size); return crc; } /// print options to log file void print_opt(cmd_opt opt) { int debug = opt.debug; if (opt.clone) log_mesg(1, 0, 0, debug, "MODE: clone\n"); else if (opt.restore) log_mesg(1, 0, 0, debug, "MODE: restore\n"); else if (opt.dd) log_mesg(1, 0, 0, debug, "MODE: device to device\n"); else if (opt.domain) log_mesg(1, 0, 0, debug, "MODE: create domain log for ddrescue\n"); else if (opt.ddd) log_mesg(1, 0, 0, debug, "MODE: work like command dd\n"); log_mesg(1, 0, 0, debug, "DEBUG: %i\n", opt.debug); log_mesg(1, 0, 0, debug, "SOURCE: %s\n", opt.source); log_mesg(1, 0, 0, debug, "TARGET: %s\n", opt.target); log_mesg(1, 0, 0, debug, "OVERWRITE: %i\n", opt.overwrite); log_mesg(1, 0, 0, debug, "RESCUE: %i\n", opt.rescue); log_mesg(1, 0, 0, debug, "CHECK: %i\n", opt.check); log_mesg(1, 0, 0, debug, "QUIET: %i\n", opt.quiet); log_mesg(1, 0, 0, debug, "FRESH: %i\n", opt.fresh); log_mesg(1, 0, 0, debug, "FORCE: %i\n", opt.force); #ifdef HAVE_LIBNCURSESW log_mesg(1, 0, 0, debug, "NCURSES: %i\n", opt.ncurses); #endif log_mesg(1, 0, 0, debug, "OFFSET DOMAIN: 0x%llX\n", opt.offset_domain); opt.note[NOTE_SIZE-1] = '\0'; log_mesg(1, 0, 0, debug, "NOTE: %s\n", opt.note); } /// print partclone info void print_partclone_info(cmd_opt opt) { int debug = opt.debug; setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); log_mesg(0, 0, 1, debug, _("Partclone v%s http://partclone.org\n"), VERSION); if (opt.chkimg) log_mesg(0, 0, 1, debug, _("Starting to check image (%s)\n"), opt.source); else if (opt.clone) log_mesg(0, 0, 1, debug, _("Starting to clone device (%s) to image (%s)\n"), opt.source, opt.target); else if(opt.restore) log_mesg(0, 0, 1, debug, _("Starting to restore image (%s) to device (%s)\n"), opt.source, opt.target); else if(opt.dd) log_mesg(0, 0, 1, debug, _("Starting to back up device(%s) to device(%s)\n"), opt.source, opt.target); else if (opt.domain) log_mesg(0, 0, 1, debug, _("Starting to map device (%s) to domain log (%s)\n"), opt.source, opt.target); else if (opt.ddd) log_mesg(0, 0, 1, debug, _("Starting to clone/restore (%s) to (%s) with dd mode\n"), opt.source, opt.target); else if (opt.info) log_mesg(0, 0, 1, debug, _("Display image information\n")); else log_mesg(0, 0, 1, debug, "Unknown mode\n"); if ( strlen(opt.note) > 0 ){ opt.note[NOTE_SIZE-1] = '\0'; log_mesg(0, 0, 1, debug, "note: %s\n", opt.note); } } /// print image head void print_image_hdr_info(image_head image_hdr, cmd_opt opt) { int block_s = image_hdr.block_size; unsigned long long total = image_hdr.totalblock; unsigned long long used = image_hdr.usedblocks; int debug = opt.debug; char size_str[11]; setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); log_mesg(0, 0, 1, debug, _("File system: %s\n"), image_hdr.fs); print_readable_size_str(total*block_s, size_str); log_mesg(0, 0, 1, debug, _("Device size: %s = %llu Blocks\n"), size_str, total); print_readable_size_str(used*block_s, size_str); log_mesg(0, 0, 1, debug, _("Space in use: %s = %llu Blocks\n"), size_str, used); print_readable_size_str((total-used)*block_s, size_str); log_mesg(0, 0, 1, debug, _("Free Space: %s = %llu Blocks\n"), size_str, (total-used)); log_mesg(0, 0, 1, debug, _("Block size: %i Byte\n"), block_s); } /// print finish message void print_finish_info(cmd_opt opt) { int debug = opt.debug; setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); if (opt.chkimg) log_mesg(0, 0, 1, debug, _("Partclone successfully checked the image (%s)\n"), opt.source); else if (opt.clone) log_mesg(0, 0, 1, debug, _("Partclone successfully cloned the device (%s) to the image (%s)\n"), opt.source, opt.target); else if (opt.restore) log_mesg(0, 0, 1, debug, _("Partclone successfully restored the image (%s) to the device (%s)\n"), opt.source, opt.target); else if (opt.dd) log_mesg(0, 0, 1, debug, _("Partclone successfully cloned the device (%s) to the device (%s)\n"), opt.source, opt.target); else if (opt.domain) log_mesg(0, 0, 1, debug, _("Partclone successfully mapped the device (%s) to the domain log (%s)\n"), opt.source, opt.target); } partclone-0.2.86/src/partclone.h000066400000000000000000000122231262102574200165260ustar00rootroot00000000000000/** * partclone.h - Part of Partclone project. * * Copyright (c) 2007~ Thomas Tsai * * function and structure used by main. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ #include #include #include #include #include #include #include #include #include #include "bitmap.h" #define IMAGE_MAGIC "partclone-image" #define IMAGE_MAGIC_SIZE 15 #define FS_MAGIC_SIZE 15 #define reiserfs_MAGIC "REISERFS" #define reiser4_MAGIC "REISER4" #define xfs_MAGIC "XFS" #define extfs_MAGIC "EXTFS" #define ext2_MAGIC "EXT2" #define ext3_MAGIC "EXT3" #define ext4_MAGIC "EXT4" #define hfsplus_MAGIC "HFS Plus" #define fat_MAGIC "FAT" #define exfat_MAGIC "EXFAT" #define ntfs_MAGIC "NTFS" #define ufs_MAGIC "UFS" #define vmfs_MAGIC "VMFS" #define jfs_MAGIC "JFS" #define btrfs_MAGIC "BTRFS" #define minix_MAGIC "MINIX" #define f2fs_MAGIC "F2FS" #define nilfs_MAGIC "NILFS" #define raw_MAGIC "raw" #define IMAGE_VERSION "0001" #define VERSION_SIZE 4 #define DEFAULT_BUFFER_SIZE 1048576 #define PART_SECTOR_SIZE 512 #define CRC_SIZE 4 #define NOTE_SIZE 128 // Reference: ntfsclone.c #define KBYTE (1000) #define MBYTE (1000 * 1000) #define GBYTE (1000 * 1000 * 1000) #define print_size(a, b) (((a) + (b - 1)) / (b)) // define read and write #define read_all(f, b, s, o) io_all((f), (b), (s), 0, (o)) #define write_all(f, b, s, o) io_all((f), (b), (s), 1, (o)) // progress flag #define BITMAP 1 #define IO 2 #define NO_BLOCK_DETAIL 3 #ifdef crc32 #undef crc32 #endif char *EXECNAME; unsigned long long rescue_write_size; /** * option * structure smd_opt * usage - print message "how to use this" * parse_options - get parameter from agrc, argv */ struct cmd_opt { int clone; int restore; int dd; int ddd; int domain; int chkimg; int info; int debug; char* source; char* target; char* logfile; char note[NOTE_SIZE]; int overwrite; int rescue; int check; int ncurses; int force; int ignore_fschk; int ignore_crc; int quiet; int no_block_detail; int restore_raw_file; int skip_write_error; int buffer_size; unsigned long offset; unsigned long fresh; unsigned long long offset_domain; }; typedef struct cmd_opt cmd_opt; extern void usage(void); extern void print_version(void); extern void parse_options(int argc, char **argv, cmd_opt* opt); /** * Ncurses Text User Interface * open_ncurses - open text window * close_ncurses - close text window */ extern int open_ncurses(); extern void close_ncurses(); /** * debug message * open_log - to open file /var/log/partclone.log * log_mesg - write log to the file * - write log and exit * - write to stderr... */ extern void open_log(char* source); extern void log_mesg(int lerrno, int lexit, int only_debug, int debug, const char *fmt, ...); extern void close_log(); extern int io_all(int *fd, char *buffer, unsigned long long count, int do_write, cmd_opt *opt); extern void sync_data(int fd, cmd_opt* opt); extern void rescue_sector(int *fd, unsigned long long pos, char *buff, cmd_opt *opt); /** * for restore used functions * restore_image_hdr - get image_head from image file * get_image_bitmap - read bitmap data from image file */ struct image_head { char magic[IMAGE_MAGIC_SIZE]; char fs[FS_MAGIC_SIZE]; char version[VERSION_SIZE]; int block_size; unsigned long long device_size; unsigned long long totalblock; unsigned long long usedblocks; char buff[4096]; }; typedef struct image_head image_head; extern void restore_image_hdr(int* ret, cmd_opt* opt, image_head* image_hdr); extern void get_image_hdr(int* ret, cmd_opt opt, image_head image_hdr, unsigned long* bitmap); extern void get_image_bitmap(int* ret, cmd_opt opt, image_head image_hdr, unsigned long* bitmap); /** * for open and close * open_source - open device or image or stdin * open_target - open device or image or stdout * * the data string * clone: read from device to image/stdout * restore: read from image/stdin to device * dd: read from device to device !! not complete * */ extern int open_source(char* source, cmd_opt* opt); extern int open_target(char* target, cmd_opt* opt); /// check partition size extern int check_size(int* ret, unsigned long long size); /// check free space extern void check_free_space(int* ret, unsigned long long size); /// check free memory size extern int check_mem_size(image_head image_hdr, cmd_opt opt, unsigned long long *mem_size); /// generate crc32 code unsigned long crc32(unsigned long crc, char *buf, int size); /// print partclone info extern void print_partclone_info(cmd_opt opt); /// print image_head extern void print_image_hdr_info(image_head image_hdr, cmd_opt opt); /// print option extern void print_opt(cmd_opt opt); /// print finish mesg extern void print_finish_info(cmd_opt opt); /// get partition size extern unsigned long long get_partition_size(int* ret); partclone-0.2.86/src/progress.c000066400000000000000000000230541262102574200164020ustar00rootroot00000000000000/** * progress.c - part of Partclone project * * Copyright (c) 2007~ Thomas Tsai * * progress bar * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ #include #include #include #include #include #include #include "config.h" #include "progress.h" #include "gettext.h" #define _(STRING) gettext(STRING) #include "partclone.h" #ifdef HAVE_LIBNCURSESW #include extern WINDOW *p_win; extern WINDOW *bar_win; extern WINDOW *tbar_win; int color_support = 1; int BUFSIZE = 50; #endif int PUI; unsigned long RES=0; /// initial progress bar extern void progress_init(struct progress_bar *prog, int start, unsigned long long stop, unsigned long long total, int flag, int size) { memset(prog, 0, sizeof(progress_bar)); prog->start = start; prog->stop = stop; prog->total = total; prog->unit = 100.0 / (stop - start); prog->total_unit = 100.0 / (total - start); prog->initial_time = time(0); prog->resolution_time = time(0); prog->interval_time = 1; prog->block_size = size; if (RES){ prog->interval_time = RES; } prog->rate = 0.0; prog->pui = PUI; prog->flag = flag; } /// open progress interface extern int open_pui(int pui, unsigned long res){ int tui = 0; if (pui == NCURSES){ tui = open_ncurses(); if (tui == 0){ close_ncurses(); PUI = TEXT; pui = TEXT; } } else if (pui == DIALOG){ tui = 1; } PUI = pui; RES = res; return tui; } /// close progress interface extern void close_pui(int pui){ if (pui == NCURSES){ close_ncurses(); } } extern void update_pui(struct progress_bar *prog, unsigned long long copied, unsigned long long current, int done){ if (done != 1) { if ((difftime(time(0), prog->resolution_time) < prog->interval_time) && copied != 0) return; } if (prog->pui == NCURSES) Ncurses_progress_update(prog, copied, current, done); else if (prog->pui == TEXT) progress_update(prog, copied, current, done); } static void calculate_speed(struct progress_bar *prog, unsigned long long copied, unsigned long long current, int done, prog_stat_t *prog_stat){ char *format = "%H:%M:%S"; uint64_t speedps = 1; uint64_t speed = 1; double dspeed = 1.0; float percent = 1.0; time_t remained; time_t elapsed; char Rformated[12], Eformated[12]; char speed_unit[] = " "; struct tm *Rtm, *Etm; uint64_t gbyte=1000000000.0; uint64_t mbyte=1000000; uint64_t kbyte=1000; percent = prog->unit * copied; if (percent <= 0) percent = 1; else if (percent >= 100) percent = 99.99; elapsed = (time(0) - prog->initial_time); if (elapsed <= 0) elapsed = 1; speedps = prog->block_size * copied / elapsed; speed = speedps * 60.0; prog_stat->percent = percent; if (speed >= gbyte){ dspeed = (double)speed / (double)gbyte; strncpy(speed_unit, "GB", 3); strncpy(prog_stat->speed_unit, speed_unit, 3); }else if (speed >= mbyte){ dspeed = (double)speed / (double)mbyte; strncpy(speed_unit, "MB", 3); strncpy(prog_stat->speed_unit, speed_unit, 3); }else if (speed >= kbyte){ dspeed = (double)speed / (double)kbyte; strncpy(speed_unit, "KB", 3); strncpy(prog_stat->speed_unit, speed_unit, 3); }else{ dspeed = speed; strncpy(speed_unit, "byte", 5); strncpy(prog_stat->speed_unit, speed_unit, 5); } prog_stat->total_percent = prog->total_unit * current; prog_stat->speed = dspeed; if (done != 1){ remained = (time_t)((elapsed/percent*100) - elapsed); if ((unsigned int)remained > 86400){ snprintf(Rformated, sizeof(Rformated), " > %3i hrs ", ((int)remained/3600)); }else{ Rtm = gmtime(&remained); strftime(Rformated, sizeof(Rformated), format, Rtm); } if ((unsigned int)elapsed > 86400){ snprintf(Eformated, sizeof(Eformated), " > %3i hrs ", ((int)elapsed/3600)); }else{ Etm = gmtime(&elapsed); strftime(Eformated, sizeof(Eformated), format, Etm); } } else { prog_stat->percent=100; remained = (time_t)0; Rtm = gmtime(&remained); strftime(Rformated, sizeof(Rformated), format, Rtm); if ((unsigned int)elapsed > 86400){ snprintf(Eformated, sizeof(Eformated), " > %3i hrs ", ((int)elapsed/3600)); }else{ Etm = gmtime(&elapsed); strftime(Eformated, sizeof(Eformated), format, Etm); } } strncpy(prog_stat->Eformated, Eformated, sizeof(prog_stat->Eformated)); strncpy(prog_stat->Rformated, Rformated, sizeof(prog_stat->Rformated)); } /// update information at progress bar extern void progress_update(struct progress_bar *prog, unsigned long long copied, unsigned long long current, int done) { char clear_buf = ' '; prog_stat_t prog_stat; memset(&prog_stat, 0, sizeof(prog_stat_t)); calculate_speed(prog, copied, current, done, &prog_stat); if (done != 1){ prog->resolution_time = time(0); setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); fprintf(stderr, _("\r%80c\rElapsed: %s, Remaining: %s, Completed: %6.2f%%"), clear_buf, prog_stat.Eformated, prog_stat.Rformated, prog_stat.percent); if((prog->flag == IO) || (prog->flag == NO_BLOCK_DETAIL)) fprintf(stderr, _(", %6.2f%s/min,"), prog_stat.speed, prog_stat.speed_unit); if(prog->flag == IO) fprintf(stderr, "\n\r%80c\rcurrent block: %10lld, total block: %10lld, Complete: %6.2f%%%s\r", clear_buf, current, prog->total, prog_stat.total_percent, "\x1b[A"); } else { setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); fprintf(stderr, _("\r%80c\rElapsed: %s, Remaining: %s, Completed: 100.00%%"), clear_buf, prog_stat.Eformated, prog_stat.Rformated); if((prog->flag == IO) || (prog->flag == NO_BLOCK_DETAIL)) fprintf(stderr, _(", Rate: %6.2f%s/min,"), prog_stat.speed, prog_stat.speed_unit); if(prog->flag == IO) fprintf(stderr, "\n\r%80c\rcurrent block: %10lld, total block: %10lld, Complete: 100.00%%\r", clear_buf, current, prog->total); fprintf(stderr, _("\nTotal Time: %s, "), prog_stat.Eformated); if(prog->flag == IO) fprintf(stderr, _("Ave. Rate: %6.1f%s/min, "), prog_stat.speed, prog_stat.speed_unit); fprintf(stderr, _("%s"), "100.00% completed!\n"); } } /// update information at ncurses mode extern void Ncurses_progress_update(struct progress_bar *prog, unsigned long long copied, unsigned long long current, int done) { #ifdef HAVE_LIBNCURSESW char *block = " "; int x = 0; char blockbuf[BUFSIZE]; prog_stat_t prog_stat; memset(&prog_stat, 0, sizeof(prog_stat_t)); calculate_speed(prog, copied, current, done, &prog_stat); /// set bar color init_pair(4, COLOR_RED, COLOR_RED); init_pair(5, COLOR_WHITE, COLOR_BLUE); init_pair(6, COLOR_WHITE, COLOR_RED); werase(p_win); werase(bar_win); if (done != 1){ prog->resolution_time = time(0); mvwprintw(p_win, 0, 0, _("Elapsed: %s Remaining: %s ") , prog_stat.Eformated, prog_stat.Rformated); if((prog->flag == IO) || (prog->flag == NO_BLOCK_DETAIL)) mvwprintw(p_win, 0, 40, _("Rate: %6.2f%s/min"), prog_stat.speed, prog_stat.speed_unit); if (prog->flag == IO) mvwprintw(p_win, 1, 0, _("Current Block: %llu Total Block: %llu ") , current, prog->total); if (prog->flag == IO) mvwprintw(p_win, 3, 0, "Data Block Process:"); else if (prog->flag == BITMAP) mvwprintw(p_win, 3, 0, "Calculating Bitmap Process:"); wattrset(bar_win, COLOR_PAIR(4)); x = snprintf(blockbuf, BUFSIZE, "%.*s", (unsigned int)(prog_stat.percent*0.5), block); if ( x < 0 ) fprintf(stderr, "ncurses update error\n"); mvwprintw(bar_win, 0, 0, "%s", blockbuf); wattroff(bar_win, COLOR_PAIR(4)); mvwprintw(p_win, 4, 52, "%6.2f%%", prog_stat.percent); if (prog->flag == IO) { werase(tbar_win); mvwprintw(p_win, 6, 0, "Total Block Process:"); wattrset(tbar_win, COLOR_PAIR(4)); x = snprintf(blockbuf, BUFSIZE, "%.*s", (unsigned int)(prog_stat.total_percent*0.5), block); if ( x < 0 ) fprintf(stderr, "ncurses update error\n"); mvwprintw(tbar_win, 0, 0, "%s", blockbuf); wattroff(tbar_win, COLOR_PAIR(4)); mvwprintw(p_win, 7, 52, "%6.2f%%", prog_stat.total_percent); } wrefresh(p_win); wrefresh(bar_win); wrefresh(tbar_win); } else { mvwprintw(p_win, 0, 0, _("Total Time: %s Remaining: %s "), prog_stat.Eformated, prog_stat.Rformated); if((prog->flag == IO) || (prog->flag == NO_BLOCK_DETAIL)) mvwprintw(p_win, 1, 0, _("Ave. Rate: %6.2f%s/min"), prog_stat.speed, prog_stat.speed_unit); if (prog->flag == IO) mvwprintw(p_win, 3, 0, "Data Block Process:"); else if (prog->flag == BITMAP) mvwprintw(p_win, 3, 0, "Calculating Bitmap Process:"); wattrset(bar_win, COLOR_PAIR(4)); mvwprintw(bar_win, 0, 0, "%50s", " "); wattroff(bar_win, COLOR_PAIR(4)); mvwprintw(p_win, 4, 52, "100.00%%"); if (prog->flag == IO) { werase(tbar_win); mvwprintw(p_win, 6, 0, "Total Block Process:"); wattrset(tbar_win, COLOR_PAIR(4)); mvwprintw(tbar_win, 0, 0, "%50s", " "); wattroff(tbar_win, COLOR_PAIR(4)); mvwprintw(p_win, 7, 52, "100.00%%"); } wrefresh(p_win); wrefresh(bar_win); wrefresh(tbar_win); refresh(); sleep(1); } #endif } partclone-0.2.86/src/progress.h000066400000000000000000000032561262102574200164110ustar00rootroot00000000000000/** * progress.h - part of Partclone project * * Copyright (c) 2007~ Thomas Tsai * * progress bar * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ #include //#include // progress display mode #define TEXT 0 #define NCURSES 1 #define DIALOG 2 /// the progress bar structure struct progress_bar { int start; unsigned long long stop; unsigned long long total; unsigned long long resolution; int block_size; float rate; time_t initial_time; time_t resolution_time; time_t interval_time; float unit; float total_unit; int pui; int flag; }; typedef struct progress_bar progress_bar; struct prog_stat_t{ char Eformated[12]; char Rformated[12]; float percent; float total_percent; float speed; char speed_unit[5]; }; typedef struct prog_stat_t prog_stat_t; extern int open_pui(int pui, unsigned long res); extern void close_pui(int pui); extern void update_pui(struct progress_bar *prog, unsigned long long copied, unsigned long long current, int done); /// initial progress bar extern void progress_init(struct progress_bar *prog, int start, unsigned long long stop, unsigned long long total, int flag, int size); /// update number extern void progress_update(struct progress_bar *prog, unsigned long long copied, unsigned long long current, int done); extern void Ncurses_progress_update(struct progress_bar *prog, unsigned long long copied, unsigned long long current, int done); partclone-0.2.86/src/reiser4clone.c000066400000000000000000000116721262102574200171370ustar00rootroot00000000000000/** * reiser4clone.c - part of Partclone project * * Copyright (c) 2007~ Thomas Tsai * * read reiserfs super block and bitmap * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "partclone.h" #include "reiser4clone.h" #include "progress.h" #include "fs_common.h" aal_device_t *fs_device; reiser4_fs_t *fs = NULL; reiser4_format_t *format; char *EXECNAME = "partclone.reiser4"; extern fs_cmd_opt fs_opt; /// open device static void fs_open(char* device){ unsigned long long int state, extended; if (libreiser4_init()) { log_mesg(0, 1, 1, fs_opt.debug, "%s: Can't initialize libreiser4.\n", __FILE__); } if (!(fs_device = aal_device_open(&file_ops, device, 512, O_RDONLY))) { log_mesg(0, 1, 1, fs_opt.debug, "%s: Cannot open the partition (%s).\n", __FILE__, device); } if (!(fs = reiser4_fs_open(fs_device, 0))) { log_mesg(0, 1, 1, fs_opt.debug, "%s: Can't open reiser4 on %s\n", __FILE__, device); } //reiser4_opset_profile(fs->tree->ent.opset); if (!(fs->journal = reiser4_journal_open(fs, fs_device))) { log_mesg(0, 1, 1, fs_opt.debug, "%s: Can't open journal on %s", __FILE__, device); } state = get_ss_status(STATUS(fs->status)); extended = get_ss_extended(STATUS(fs->status)); if(fs_opt.ignore_fschk){ log_mesg(1, 0, 0, fs_opt.debug, "%s: Ignore filesystem check\n", __FILE__); }else{ if (!state) log_mesg(1, 0, 0, fs_opt.debug, "%s: REISER4: FS marked consistent\n", __FILE__); if (state) log_mesg(3, 0, 0, fs_opt.debug, "%s: REISER4: stat : %i\n", __FILE__, state); if (state != FS_OK) log_mesg(0, 1, 1, fs_opt.debug, "%s: Filesystem isn't in valid state. May be it is not cleanly unmounted.\n\n", __FILE__); if (extended) log_mesg(3, 0, 0, fs_opt.debug, "%s: Extended status: %0xllx\n", extended, __FILE__); } //reiser4_opset_profile(fs->tree->ent.opset); fs->format = reiser4_format_open(fs); } /// close device static void fs_close(){ reiser4_fs_close(fs); aal_device_close(fs_device); } /// readbitmap - read bitmap extern void readbitmap(char* device, image_head image_hdr, unsigned long* bitmap, int pui) { reiser4_bitmap_t *fs_bitmap; unsigned long long bit, block, bused = 0, bfree = 0; int start = 0; int bit_size = 1; fs_open(device); fs_bitmap = reiser4_bitmap_create(reiser4_format_get_len(fs->format)); reiser4_alloc_extract(fs->alloc, fs_bitmap); /// init progress progress_bar prog; /// progress_bar structure defined in progress.h progress_init(&prog, start, image_hdr.totalblock, image_hdr.totalblock, BITMAP, bit_size); for(bit = 0; bit < reiser4_format_get_len(fs->format); bit++){ block = bit ; if(reiser4_bitmap_test(fs_bitmap, bit)){ bused++; pc_set_bit(block, bitmap); log_mesg(3, 0, 0, fs_opt.debug, "%s: bitmap is used %llu", __FILE__, block); } else { pc_clear_bit(block, bitmap); bfree++; log_mesg(3, 0, 0, fs_opt.debug, "%s: bitmap is free %llu", __FILE__, block); } /// update progress update_pui(&prog, bit, bit, 0); } if(bfree != reiser4_format_get_free(fs->format)) log_mesg(0, 1, 1, fs_opt.debug, "%s: bitmap free count err, bfree:%llu, sfree=%llu\n", __FILE__, bfree, reiser4_format_get_free(fs->format)); fs_close(); /// update progress update_pui(&prog, 1, 1, 1); } /// read super block and write to image head extern void initial_image_hdr(char* device, image_head* image_hdr) { reiser4_bitmap_t *fs_bitmap; unsigned long long free_blocks=0; fs_open(device); fs_bitmap = reiser4_bitmap_create(reiser4_format_get_len(fs->format)); reiser4_alloc_extract(fs->alloc, fs_bitmap); free_blocks = reiser4_format_get_free(fs->format); strncpy(image_hdr->magic, IMAGE_MAGIC, IMAGE_MAGIC_SIZE); strncpy(image_hdr->fs, reiser4_MAGIC, FS_MAGIC_SIZE); image_hdr->block_size = (int)get_ms_blksize(SUPER(fs->master)); image_hdr->totalblock = (unsigned long long)reiser4_format_get_len(fs->format); image_hdr->usedblocks = (unsigned long long)(reiser4_format_get_len(fs->format) - free_blocks); image_hdr->device_size =(unsigned long long)(image_hdr->block_size * image_hdr->totalblock); fs_close(); } partclone-0.2.86/src/reiser4clone.h000066400000000000000000000012121262102574200171310ustar00rootroot00000000000000/** * reiser4clone.h - part of Partclone project * * Copyright (c) 2007~ Thomas Tsai * * read reiser4 super block and bitmap * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ /// readbitmap - read bitmap extern void readbitmap(char* device, image_head image_hdr, unsigned long* bitmap, int pui); /// read super block and write to image head extern void initial_image_hdr(char* device, image_head* image_hdr); partclone-0.2.86/src/reiserfsclone.c000066400000000000000000000072251262102574200174030ustar00rootroot00000000000000/** * reiserfsclone.c - part of Partclone project * * Copyright (c) 2007~ Thomas Tsai * * read reiserfs super block and bitmap * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "partclone.h" #include "reiserfsclone.h" #include "progress.h" #include "fs_common.h" dal_t *dal; reiserfs_fs_t *fs; char *EXECNAME = "partclone.reiserfs"; extern fs_cmd_opt fs_opt; /// open device static void fs_open(char* device){ if (!(dal = (dal_t*)file_dal_open(device, DEFAULT_BLOCK_SIZE, O_RDONLY))) { log_mesg(0, 1, 1, fs_opt.debug, "%s: Couldn't create device abstraction for %s.\n", __FILE__, device); } if (!(fs = reiserfs_fs_open(dal, dal))) { log_mesg(0, 1, 1, fs_opt.debug, "%s: Couldn't open filesystem on %s.\n", __FILE__, device); } if(fs_opt.ignore_fschk){ log_mesg(1, 0, 0, fs_opt.debug, "%s: Ignore filesystem check\n", __FILE__); }else{ if (get_sb_umount_state(fs->super) != FS_CLEAN) log_mesg(0, 1, 1, fs_opt.debug, "%s: Filesystem isn't in valid state. May be it is not cleanly unmounted.\n\n", __FILE__); } } /// close device static void fs_close(){ reiserfs_fs_close(fs); file_dal_close(dal); } /// readbitmap - read bitmap extern void readbitmap(char* device, image_head image_hdr, unsigned long* bitmap, int pui) { reiserfs_bitmap_t *fs_bitmap; reiserfs_tree_t *tree; unsigned long long blk = 0; unsigned long long bused = 0, bfree = 0; int start = 0; int bit_size = 1; int done = 0; fs_open(device); tree = reiserfs_fs_tree(fs); fs_bitmap = tree->fs->bitmap; /// init progress progress_bar bprog; /// progress_bar structure defined in progress.h progress_init(&bprog, start, fs->super->s_v1.sb_block_count, fs->super->s_v1.sb_block_count, BITMAP, bit_size); for( blk = 0; blk < (unsigned long long)fs->super->s_v1.sb_block_count; blk++ ){ log_mesg(3, 0, 0, fs_opt.debug, "%s: block sb_block_count %llu\n", __FILE__, fs->super->s_v1.sb_block_count); log_mesg(3, 0, 0, fs_opt.debug, "%s: block bitmap check %llu\n", __FILE__, blk); if(reiserfs_tools_test_bit(blk, fs_bitmap->bm_map)){ bused++; pc_set_bit(blk, bitmap); }else{ bfree++; pc_clear_bit(blk, bitmap); } /// update progress update_pui(&bprog, blk, blk, done); } if(bfree != fs->super->s_v1.sb_free_blocks) log_mesg(0, 1, 1, fs_opt.debug, "%s: bitmap free count err, free:%i\n", __FILE__, bfree); fs_close(); /// update progress update_pui(&bprog, 1, 1, 1); } /// read super block and write to image head extern void initial_image_hdr(char* device, image_head* image_hdr) { fs_open(device); strncpy(image_hdr->magic, IMAGE_MAGIC, IMAGE_MAGIC_SIZE); strncpy(image_hdr->fs, reiserfs_MAGIC, FS_MAGIC_SIZE); image_hdr->block_size = (int)fs->super->s_v1.sb_block_size; image_hdr->totalblock = (unsigned long long)fs->super->s_v1.sb_block_count; image_hdr->usedblocks = (unsigned long long)(fs->super->s_v1.sb_block_count - fs->super->s_v1.sb_free_blocks); image_hdr->device_size = (unsigned long long)(image_hdr->block_size * image_hdr->totalblock); fs_close(); } partclone-0.2.86/src/reiserfsclone.h000066400000000000000000000012141262102574200174000ustar00rootroot00000000000000/** * reiserfsclone.h - part of Partclone project * * Copyright (c) 2007~ Thomas Tsai * * read reiserfs super block and bitmap * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ /// readbitmap - read bitmap extern void readbitmap(char* device, image_head image_hdr, unsigned long* bitmap, int pui); /// read super block and write to image head extern void initial_image_hdr(char* device, image_head* image_hdr); partclone-0.2.86/src/ufs/000077500000000000000000000000001262102574200151635ustar00rootroot00000000000000partclone-0.2.86/src/ufs/ffs/000077500000000000000000000000001262102574200157415ustar00rootroot00000000000000partclone-0.2.86/src/ufs/ffs/fs.h000066400000000000000000000645671262102574200165440ustar00rootroot00000000000000/*- * Copyright (c) 1982, 1986, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)fs.h 8.13 (Berkeley) 3/21/95 * $FreeBSD: src/sys/ufs/ffs/fs.h,v 1.49.8.1 2009/04/15 03:14:26 kensmith Exp $ */ #ifndef _UFS_FFS_FS_H_ #define _UFS_FFS_FS_H_ #include #include /* * Each disk drive contains some number of filesystems. * A filesystem consists of a number of cylinder groups. * Each cylinder group has inodes and data. * * A filesystem is described by its super-block, which in turn * describes the cylinder groups. The super-block is critical * data and is replicated in each cylinder group to protect against * catastrophic loss. This is done at `newfs' time and the critical * super-block data does not change, so the copies need not be * referenced further unless disaster strikes. * * For filesystem fs, the offsets of the various blocks of interest * are given in the super block as: * [fs->fs_sblkno] Super-block * [fs->fs_cblkno] Cylinder group block * [fs->fs_iblkno] Inode blocks * [fs->fs_dblkno] Data blocks * The beginning of cylinder group cg in fs, is given by * the ``cgbase(fs, cg)'' macro. * * Depending on the architecture and the media, the superblock may * reside in any one of four places. For tiny media where every block * counts, it is placed at the very front of the partition. Historically, * UFS1 placed it 8K from the front to leave room for the disk label and * a small bootstrap. For UFS2 it got moved to 64K from the front to leave * room for the disk label and a bigger bootstrap, and for really piggy * systems we check at 256K from the front if the first three fail. In * all cases the size of the superblock will be SBLOCKSIZE. All values are * given in byte-offset form, so they do not imply a sector size. The * SBLOCKSEARCH specifies the order in which the locations should be searched. */ #define SBLOCK_FLOPPY 0 #define SBLOCK_UFS1 8192 #define SBLOCK_UFS2 65536 #define SBLOCK_PIGGY 262144 #define SBLOCKSIZE 8192 #define SBLOCKSEARCH \ { SBLOCK_UFS2, SBLOCK_UFS1, SBLOCK_FLOPPY, SBLOCK_PIGGY, -1 } /* * Max number of fragments per block. This value is NOT tweakable. */ #define MAXFRAG 8 /* * Addresses stored in inodes are capable of addressing fragments * of `blocks'. File system blocks of at most size MAXBSIZE can * be optionally broken into 2, 4, or 8 pieces, each of which is * addressable; these pieces may be DEV_BSIZE, or some multiple of * a DEV_BSIZE unit. * * Large files consist of exclusively large data blocks. To avoid * undue wasted disk space, the last data block of a small file may be * allocated as only as many fragments of a large block as are * necessary. The filesystem format retains only a single pointer * to such a fragment, which is a piece of a single large block that * has been divided. The size of such a fragment is determinable from * information in the inode, using the ``blksize(fs, ip, lbn)'' macro. * * The filesystem records space availability at the fragment level; * to determine block availability, aligned fragments are examined. */ /* * MINBSIZE is the smallest allowable block size. * In order to insure that it is possible to create files of size * 2^32 with only two levels of indirection, MINBSIZE is set to 4096. * MINBSIZE must be big enough to hold a cylinder group block, * thus changes to (struct cg) must keep its size within MINBSIZE. * Note that super blocks are always of size SBSIZE, * and that both SBSIZE and MAXBSIZE must be >= MINBSIZE. */ #define MINBSIZE 4096 /* * The path name on which the filesystem is mounted is maintained * in fs_fsmnt. MAXMNTLEN defines the amount of space allocated in * the super block for this name. */ #define MAXMNTLEN 468 /* * The volume name for this filesystem is maintained in fs_volname. * MAXVOLLEN defines the length of the buffer allocated. */ #define MAXVOLLEN 32 /* * There is a 128-byte region in the superblock reserved for in-core * pointers to summary information. Originally this included an array * of pointers to blocks of struct csum; now there are just a few * pointers and the remaining space is padded with fs_ocsp[]. * * NOCSPTRS determines the size of this padding. One pointer (fs_csp) * is taken away to point to a contiguous array of struct csum for * all cylinder groups; a second (fs_maxcluster) points to an array * of cluster sizes that is computed as cylinder groups are inspected, * and the third points to an array that tracks the creation of new * directories. A fourth pointer, fs_active, is used when creating * snapshots; it points to a bitmap of cylinder groups for which the * free-block bitmap has changed since the snapshot operation began. */ #define NOCSPTRS ((128 / sizeof(void *)) - 4) /* * A summary of contiguous blocks of various sizes is maintained * in each cylinder group. Normally this is set by the initial * value of fs_maxcontig. To conserve space, a maximum summary size * is set by FS_MAXCONTIG. */ #define FS_MAXCONTIG 16 /* * MINFREE gives the minimum acceptable percentage of filesystem * blocks which may be free. If the freelist drops below this level * only the superuser may continue to allocate blocks. This may * be set to 0 if no reserve of free blocks is deemed necessary, * however throughput drops by fifty percent if the filesystem * is run at between 95% and 100% full; thus the minimum default * value of fs_minfree is 5%. However, to get good clustering * performance, 10% is a better choice. hence we use 10% as our * default value. With 10% free space, fragmentation is not a * problem, so we choose to optimize for time. */ #define MINFREE 8 #define DEFAULTOPT FS_OPTTIME /* * Grigoriy Orlov has done some extensive work to fine * tune the layout preferences for directories within a filesystem. * His algorithm can be tuned by adjusting the following parameters * which tell the system the average file size and the average number * of files per directory. These defaults are well selected for typical * filesystems, but may need to be tuned for odd cases like filesystems * being used for squid caches or news spools. */ #define AVFILESIZ 16384 /* expected average file size */ #define AFPDIR 64 /* expected number of files per directory */ /* * The maximum number of snapshot nodes that can be associated * with each filesystem. This limit affects only the number of * snapshot files that can be recorded within the superblock so * that they can be found when the filesystem is mounted. However, * maintaining too many will slow the filesystem performance, so * having this limit is a good idea. */ #define FSMAXSNAP 20 /* * Used to identify special blocks in snapshots: * * BLK_NOCOPY - A block that was unallocated at the time the snapshot * was taken, hence does not need to be copied when written. * BLK_SNAP - A block held by another snapshot that is not needed by this * snapshot. When the other snapshot is freed, the BLK_SNAP entries * are converted to BLK_NOCOPY. These are needed to allow fsck to * identify blocks that are in use by other snapshots (which are * expunged from this snapshot). */ #define BLK_NOCOPY ((ufs2_daddr_t)(1)) #define BLK_SNAP ((ufs2_daddr_t)(2)) /* * Sysctl values for the fast filesystem. */ #define FFS_ADJ_REFCNT 1 /* adjust inode reference count */ #define FFS_ADJ_BLKCNT 2 /* adjust inode used block count */ #define FFS_BLK_FREE 3 /* free range of blocks in map */ #define FFS_DIR_FREE 4 /* free specified dir inodes in map */ #define FFS_FILE_FREE 5 /* free specified file inodes in map */ #define FFS_SET_FLAGS 6 /* set filesystem flags */ #define FFS_ADJ_NDIR 7 /* adjust number of directories */ #define FFS_ADJ_NBFREE 8 /* adjust number of free blocks */ #define FFS_ADJ_NIFREE 9 /* adjust number of free inodes */ #define FFS_ADJ_NFFREE 10 /* adjust number of free frags */ #define FFS_ADJ_NUMCLUSTERS 11 /* adjust number of free clusters */ #define FFS_MAXID 12 /* number of valid ffs ids */ /* * Command structure passed in to the filesystem to adjust filesystem values. */ #define FFS_CMD_VERSION 0x19790518 /* version ID */ struct fsck_cmd { int32_t version; /* version of command structure */ int32_t handle; /* reference to filesystem to be changed */ int64_t value; /* inode or block number to be affected */ int64_t size; /* amount or range to be adjusted */ int64_t spare; /* reserved for future use */ }; /* * Per cylinder group information; summarized in blocks allocated * from first cylinder group data blocks. These blocks have to be * read in from fs_csaddr (size fs_cssize) in addition to the * super block. */ struct csum { int32_t cs_ndir; /* number of directories */ int32_t cs_nbfree; /* number of free blocks */ int32_t cs_nifree; /* number of free inodes */ int32_t cs_nffree; /* number of free frags */ }; struct csum_total { int64_t cs_ndir; /* number of directories */ int64_t cs_nbfree; /* number of free blocks */ int64_t cs_nifree; /* number of free inodes */ int64_t cs_nffree; /* number of free frags */ int64_t cs_numclusters; /* number of free clusters */ int64_t cs_spare[3]; /* future expansion */ }; /* * Super block for an FFS filesystem. */ struct fs { int32_t fs_firstfield; /* historic filesystem linked list, */ int32_t fs_unused_1; /* used for incore super blocks */ int32_t fs_sblkno; /* offset of super-block in filesys */ int32_t fs_cblkno; /* offset of cyl-block in filesys */ int32_t fs_iblkno; /* offset of inode-blocks in filesys */ int32_t fs_dblkno; /* offset of first data after cg */ int32_t fs_old_cgoffset; /* cylinder group offset in cylinder */ int32_t fs_old_cgmask; /* used to calc mod fs_ntrak */ int32_t fs_old_time; /* last time written */ int32_t fs_old_size; /* number of blocks in fs */ int32_t fs_old_dsize; /* number of data blocks in fs */ int32_t fs_ncg; /* number of cylinder groups */ int32_t fs_bsize; /* size of basic blocks in fs */ int32_t fs_fsize; /* size of frag blocks in fs */ int32_t fs_frag; /* number of frags in a block in fs */ /* these are configuration parameters */ int32_t fs_minfree; /* minimum percentage of free blocks */ int32_t fs_old_rotdelay; /* num of ms for optimal next block */ int32_t fs_old_rps; /* disk revolutions per second */ /* these fields can be computed from the others */ int32_t fs_bmask; /* ``blkoff'' calc of blk offsets */ int32_t fs_fmask; /* ``fragoff'' calc of frag offsets */ int32_t fs_bshift; /* ``lblkno'' calc of logical blkno */ int32_t fs_fshift; /* ``numfrags'' calc number of frags */ /* these are configuration parameters */ int32_t fs_maxcontig; /* max number of contiguous blks */ int32_t fs_maxbpg; /* max number of blks per cyl group */ /* these fields can be computed from the others */ int32_t fs_fragshift; /* block to frag shift */ int32_t fs_fsbtodb; /* fsbtodb and dbtofsb shift constant */ int32_t fs_sbsize; /* actual size of super block */ int32_t fs_spare1[2]; /* old fs_csmask */ /* old fs_csshift */ int32_t fs_nindir; /* value of NINDIR */ int32_t fs_inopb; /* value of INOPB */ int32_t fs_old_nspf; /* value of NSPF */ /* yet another configuration parameter */ int32_t fs_optim; /* optimization preference, see below */ int32_t fs_old_npsect; /* # sectors/track including spares */ int32_t fs_old_interleave; /* hardware sector interleave */ int32_t fs_old_trackskew; /* sector 0 skew, per track */ int32_t fs_id[2]; /* unique filesystem id */ /* sizes determined by number of cylinder groups and their sizes */ int32_t fs_old_csaddr; /* blk addr of cyl grp summary area */ int32_t fs_cssize; /* size of cyl grp summary area */ int32_t fs_cgsize; /* cylinder group size */ int32_t fs_spare2; /* old fs_ntrak */ int32_t fs_old_nsect; /* sectors per track */ int32_t fs_old_spc; /* sectors per cylinder */ int32_t fs_old_ncyl; /* cylinders in filesystem */ int32_t fs_old_cpg; /* cylinders per group */ int32_t fs_ipg; /* inodes per group */ int32_t fs_fpg; /* blocks per group * fs_frag */ /* this data must be re-computed after crashes */ struct csum fs_old_cstotal; /* cylinder summary information */ /* these fields are cleared at mount time */ int8_t fs_fmod; /* super block modified flag */ int8_t fs_clean; /* filesystem is clean flag */ int8_t fs_ronly; /* mounted read-only flag */ int8_t fs_old_flags; /* old FS_ flags */ u_char fs_fsmnt[MAXMNTLEN]; /* name mounted on */ u_char fs_volname[MAXVOLLEN]; /* volume name */ u_int64_t fs_swuid; /* system-wide uid */ int32_t fs_pad; /* due to alignment of fs_swuid */ /* these fields retain the current block allocation info */ int32_t fs_cgrotor; /* last cg searched */ void *fs_ocsp[NOCSPTRS]; /* padding; was list of fs_cs buffers */ u_int8_t *fs_contigdirs; /* (u) # of contig. allocated dirs */ struct csum *fs_csp; /* (u) cg summary info buffer */ int32_t *fs_maxcluster; /* (u) max cluster in each cyl group */ u_int *fs_active; /* (u) used by snapshots to track fs */ int32_t fs_old_cpc; /* cyl per cycle in postbl */ int32_t fs_maxbsize; /* maximum blocking factor permitted */ int64_t fs_unrefs; /* number of unreferenced inodes */ int64_t fs_sparecon64[16]; /* old rotation block list head */ int64_t fs_sblockloc; /* byte offset of standard superblock */ struct csum_total fs_cstotal; /* (u) cylinder summary information */ ufs_time_t fs_time; /* last time written */ int64_t fs_size; /* number of blocks in fs */ int64_t fs_dsize; /* number of data blocks in fs */ ufs2_daddr_t fs_csaddr; /* blk addr of cyl grp summary area */ int64_t fs_pendingblocks; /* (u) blocks being freed */ int32_t fs_pendinginodes; /* (u) inodes being freed */ int32_t fs_snapinum[FSMAXSNAP];/* list of snapshot inode numbers */ int32_t fs_avgfilesize; /* expected average file size */ int32_t fs_avgfpdir; /* expected # of files per directory */ int32_t fs_save_cgsize; /* save real cg size to use fs_bsize */ int32_t fs_sparecon32[26]; /* reserved for future constants */ int32_t fs_flags; /* see FS_ flags below */ int32_t fs_contigsumsize; /* size of cluster summary array */ int32_t fs_maxsymlinklen; /* max length of an internal symlink */ int32_t fs_old_inodefmt; /* format of on-disk inodes */ u_int64_t fs_maxfilesize; /* maximum representable file size */ int64_t fs_qbmask; /* ~fs_bmask for use with 64-bit size */ int64_t fs_qfmask; /* ~fs_fmask for use with 64-bit size */ int32_t fs_state; /* validate fs_clean field */ int32_t fs_old_postblformat; /* format of positional layout tables */ int32_t fs_old_nrpos; /* number of rotational positions */ int32_t fs_spare5[2]; /* old fs_postbloff */ /* old fs_rotbloff */ int32_t fs_magic; /* magic number */ }; /* Sanity checking. */ #ifdef CTASSERT CTASSERT(sizeof(struct fs) == 1376); #endif /* * Filesystem identification */ #define FS_UFS1_MAGIC 0x011954 /* UFS1 fast filesystem magic number */ #define FS_UFS2_MAGIC 0x19540119 /* UFS2 fast filesystem magic number */ #define FS_BAD_MAGIC 0x19960408 /* UFS incomplete newfs magic number */ #define FS_OKAY 0x7c269d38 /* superblock checksum */ #define FS_42INODEFMT -1 /* 4.2BSD inode format */ #define FS_44INODEFMT 2 /* 4.4BSD inode format */ /* * Preference for optimization. */ #define FS_OPTTIME 0 /* minimize allocation time */ #define FS_OPTSPACE 1 /* minimize disk fragmentation */ /* * Filesystem flags. * * The FS_UNCLEAN flag is set by the kernel when the filesystem was * mounted with fs_clean set to zero. The FS_DOSOFTDEP flag indicates * that the filesystem should be managed by the soft updates code. * Note that the FS_NEEDSFSCK flag is set and cleared only by the * fsck utility. It is set when background fsck finds an unexpected * inconsistency which requires a traditional foreground fsck to be * run. Such inconsistencies should only be found after an uncorrectable * disk error. A foreground fsck will clear the FS_NEEDSFSCK flag when * it has successfully cleaned up the filesystem. The kernel uses this * flag to enforce that inconsistent filesystems be mounted read-only. * The FS_INDEXDIRS flag when set indicates that the kernel maintains * on-disk auxiliary indexes (such as B-trees) for speeding directory * accesses. Kernels that do not support auxiliary indicies clear the * flag to indicate that the indicies need to be rebuilt (by fsck) before * they can be used. * * FS_ACLS indicates that ACLs are administratively enabled for the * file system, so they should be loaded from extended attributes, * observed for access control purposes, and be administered by object * owners. FS_MULTILABEL indicates that the TrustedBSD MAC Framework * should attempt to back MAC labels into extended attributes on the * file system rather than maintain a single mount label for all * objects. */ #define FS_UNCLEAN 0x01 /* filesystem not clean at mount */ #define FS_DOSOFTDEP 0x02 /* filesystem using soft dependencies */ #define FS_NEEDSFSCK 0x04 /* filesystem needs sync fsck before mount */ #define FS_INDEXDIRS 0x08 /* kernel supports indexed directories */ #define FS_ACLS 0x10 /* file system has ACLs enabled */ #define FS_MULTILABEL 0x20 /* file system is MAC multi-label */ #define FS_GJOURNAL 0x40 /* gjournaled file system */ #define FS_FLAGS_UPDATED 0x80 /* flags have been moved to new location */ /* * Macros to access bits in the fs_active array. */ #define ACTIVECGNUM(fs, cg) ((fs)->fs_active[(cg) / (NBBY * sizeof(int))]) #define ACTIVECGOFF(cg) (1 << ((cg) % (NBBY * sizeof(int)))) #define ACTIVESET(fs, cg) do { \ if ((fs)->fs_active) \ ACTIVECGNUM((fs), (cg)) |= ACTIVECGOFF((cg)); \ } while (0) #define ACTIVECLEAR(fs, cg) do { \ if ((fs)->fs_active) \ ACTIVECGNUM((fs), (cg)) &= ~ACTIVECGOFF((cg)); \ } while (0) /* * The size of a cylinder group is calculated by CGSIZE. The maximum size * is limited by the fact that cylinder groups are at most one block. * Its size is derived from the size of the maps maintained in the * cylinder group and the (struct cg) size. */ #define CGSIZE(fs) \ /* base cg */ (sizeof(struct cg) + sizeof(int32_t) + \ /* old btotoff */ (fs)->fs_old_cpg * sizeof(int32_t) + \ /* old boff */ (fs)->fs_old_cpg * sizeof(u_int16_t) + \ /* inode map */ howmany((fs)->fs_ipg, NBBY) + \ /* block map */ howmany((fs)->fs_fpg, NBBY) +\ /* if present */ ((fs)->fs_contigsumsize <= 0 ? 0 : \ /* cluster sum */ (fs)->fs_contigsumsize * sizeof(int32_t) + \ /* cluster map */ howmany(fragstoblks(fs, (fs)->fs_fpg), NBBY))) /* * The minimal number of cylinder groups that should be created. */ #define MINCYLGRPS 4 /* * Convert cylinder group to base address of its global summary info. */ #define fs_cs(fs, indx) fs_csp[indx] /* * Cylinder group block for a filesystem. */ #define CG_MAGIC 0x090255 struct cg { int32_t cg_firstfield; /* historic cyl groups linked list */ int32_t cg_magic; /* magic number */ int32_t cg_old_time; /* time last written */ int32_t cg_cgx; /* we are the cgx'th cylinder group */ int16_t cg_old_ncyl; /* number of cyl's this cg */ int16_t cg_old_niblk; /* number of inode blocks this cg */ int32_t cg_ndblk; /* number of data blocks this cg */ struct csum cg_cs; /* cylinder summary information */ int32_t cg_rotor; /* position of last used block */ int32_t cg_frotor; /* position of last used frag */ int32_t cg_irotor; /* position of last used inode */ int32_t cg_frsum[MAXFRAG]; /* counts of available frags */ int32_t cg_old_btotoff; /* (int32) block totals per cylinder */ int32_t cg_old_boff; /* (u_int16) free block positions */ int32_t cg_iusedoff; /* (u_int8) used inode map */ int32_t cg_freeoff; /* (u_int8) free block map */ int32_t cg_nextfreeoff; /* (u_int8) next available space */ int32_t cg_clustersumoff; /* (u_int32) counts of avail clusters */ int32_t cg_clusteroff; /* (u_int8) free cluster map */ int32_t cg_nclusterblks; /* number of clusters this cg */ int32_t cg_niblk; /* number of inode blocks this cg */ int32_t cg_initediblk; /* last initialized inode */ int32_t cg_unrefs; /* number of unreferenced inodes */ int32_t cg_sparecon32[2]; /* reserved for future use */ ufs_time_t cg_time; /* time last written */ int64_t cg_sparecon64[3]; /* reserved for future use */ u_int8_t cg_space[1]; /* space for cylinder group maps */ /* actually longer */ }; /* * Macros for access to cylinder group array structures */ #define cg_chkmagic(cgp) ((cgp)->cg_magic == CG_MAGIC) #define cg_inosused(cgp) \ ((u_int8_t *)((u_int8_t *)(cgp) + (cgp)->cg_iusedoff)) #define cg_blksfree(cgp) \ ((u_int8_t *)((u_int8_t *)(cgp) + (cgp)->cg_freeoff)) #define cg_clustersfree(cgp) \ ((u_int8_t *)((u_int8_t *)(cgp) + (cgp)->cg_clusteroff)) #define cg_clustersum(cgp) \ ((int32_t *)((uintptr_t)(cgp) + (cgp)->cg_clustersumoff)) /* * Turn filesystem block numbers into disk block addresses. * This maps filesystem blocks to device size blocks. */ #define fsbtodb(fs, b) ((daddr_t)(b) << (fs)->fs_fsbtodb) #define dbtofsb(fs, b) ((b) >> (fs)->fs_fsbtodb) /* * Cylinder group macros to locate things in cylinder groups. * They calc filesystem addresses of cylinder group data structures. */ #define cgbase(fs, c) (((ufs2_daddr_t)(fs)->fs_fpg) * (c)) #define cgdmin(fs, c) (cgstart(fs, c) + (fs)->fs_dblkno) /* 1st data */ #define cgimin(fs, c) (cgstart(fs, c) + (fs)->fs_iblkno) /* inode blk */ #define cgsblock(fs, c) (cgstart(fs, c) + (fs)->fs_sblkno) /* super blk */ #define cgtod(fs, c) (cgstart(fs, c) + (fs)->fs_cblkno) /* cg block */ #define cgstart(fs, c) \ ((fs)->fs_magic == FS_UFS2_MAGIC ? cgbase(fs, c) : \ (cgbase(fs, c) + (fs)->fs_old_cgoffset * ((c) & ~((fs)->fs_old_cgmask)))) /* * Macros for handling inode numbers: * inode number to filesystem block offset. * inode number to cylinder group number. * inode number to filesystem block address. */ #define ino_to_cg(fs, x) ((x) / (fs)->fs_ipg) #define ino_to_fsba(fs, x) \ ((ufs2_daddr_t)(cgimin(fs, ino_to_cg(fs, x)) + \ (blkstofrags((fs), (((x) % (fs)->fs_ipg) / INOPB(fs)))))) #define ino_to_fsbo(fs, x) ((x) % INOPB(fs)) /* * Give cylinder group number for a filesystem block. * Give cylinder group block number for a filesystem block. */ #define dtog(fs, d) ((d) / (fs)->fs_fpg) #define dtogd(fs, d) ((d) % (fs)->fs_fpg) /* * Extract the bits for a block from a map. * Compute the cylinder and rotational position of a cyl block addr. */ #define blkmap(fs, map, loc) \ (((map)[(loc) / NBBY] >> ((loc) % NBBY)) & (0xff >> (NBBY - (fs)->fs_frag))) /* * The following macros optimize certain frequently calculated * quantities by using shifts and masks in place of divisions * modulos and multiplications. */ #define blkoff(fs, loc) /* calculates (loc % fs->fs_bsize) */ \ ((loc) & (fs)->fs_qbmask) #define fragoff(fs, loc) /* calculates (loc % fs->fs_fsize) */ \ ((loc) & (fs)->fs_qfmask) #define lfragtosize(fs, frag) /* calculates ((off_t)frag * fs->fs_fsize) */ \ (((off_t)(frag)) << (fs)->fs_fshift) #define lblktosize(fs, blk) /* calculates ((off_t)blk * fs->fs_bsize) */ \ (((off_t)(blk)) << (fs)->fs_bshift) /* Use this only when `blk' is known to be small, e.g., < NDADDR. */ #define smalllblktosize(fs, blk) /* calculates (blk * fs->fs_bsize) */ \ ((blk) << (fs)->fs_bshift) #define lblkno(fs, loc) /* calculates (loc / fs->fs_bsize) */ \ ((loc) >> (fs)->fs_bshift) #define numfrags(fs, loc) /* calculates (loc / fs->fs_fsize) */ \ ((loc) >> (fs)->fs_fshift) #define blkroundup(fs, size) /* calculates roundup(size, fs->fs_bsize) */ \ (((size) + (fs)->fs_qbmask) & (fs)->fs_bmask) #define fragroundup(fs, size) /* calculates roundup(size, fs->fs_fsize) */ \ (((size) + (fs)->fs_qfmask) & (fs)->fs_fmask) #define fragstoblks(fs, frags) /* calculates (frags / fs->fs_frag) */ \ ((frags) >> (fs)->fs_fragshift) #define blkstofrags(fs, blks) /* calculates (blks * fs->fs_frag) */ \ ((blks) << (fs)->fs_fragshift) #define fragnum(fs, fsb) /* calculates (fsb % fs->fs_frag) */ \ ((fsb) & ((fs)->fs_frag - 1)) #define blknum(fs, fsb) /* calculates rounddown(fsb, fs->fs_frag) */ \ ((fsb) &~ ((fs)->fs_frag - 1)) /* * Determine the number of available frags given a * percentage to hold in reserve. */ #define freespace(fs, percentreserved) \ (blkstofrags((fs), (fs)->fs_cstotal.cs_nbfree) + \ (fs)->fs_cstotal.cs_nffree - \ (((off_t)((fs)->fs_dsize)) * (percentreserved) / 100)) /* * Determining the size of a file block in the filesystem. */ #define blksize(fs, ip, lbn) \ (((lbn) >= NDADDR || (ip)->i_size >= smalllblktosize(fs, (lbn) + 1)) \ ? (fs)->fs_bsize \ : (fragroundup(fs, blkoff(fs, (ip)->i_size)))) #define sblksize(fs, size, lbn) \ (((lbn) >= NDADDR || (size) >= ((lbn) + 1) << (fs)->fs_bshift) \ ? (fs)->fs_bsize \ : (fragroundup(fs, blkoff(fs, (size))))) /* * Number of inodes in a secondary storage block/fragment. */ #define INOPB(fs) ((fs)->fs_inopb) #define INOPF(fs) ((fs)->fs_inopb >> (fs)->fs_fragshift) /* * Number of indirects in a filesystem block. */ #define NINDIR(fs) ((fs)->fs_nindir) extern int inside[], around[]; extern u_char *fragtbl[]; #endif partclone-0.2.86/src/ufs/libufs.h000066400000000000000000000074721262102574200166320ustar00rootroot00000000000000/* * Copyright (c) 2002 Juli Mallett. All rights reserved. * * This software was written by Juli Mallett for the * FreeBSD project. Redistribution and use in source and binary forms, with * or without modification, are permitted provided that the following * conditions are met: * * 1. Redistribution of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistribution in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD: src/lib/libufs/libufs.h,v 1.12.8.1 2009/04/15 03:14:26 kensmith Exp $ */ #define MAXBSIZE 65536 /* must be power of 2 from param.h of ufs*/ #ifndef __LIBUFS_H__ #define __LIBUFS_H__ /* * libufs macros (internal, non-exported). */ #ifdef _LIBUFS #ifdef _LIBUFS_DEBUGGING /* * Trace steps through libufs, to be used at entry and erroneous return. */ #define ERROR(uufsd, str) \ do { \ fprintf(stderr, "libufs in %s", __func__); \ if (str != NULL) \ fprintf(stderr, ": %s", str); \ if (errno) \ fprintf(stderr, ": %s", strerror(errno)); \ fprintf(stderr, "\n"); \ if ((uufsd) != NULL) \ (uufsd)->d_error = str; \ } while (0) #else /* _LIBUFS_DEBUGGING */ #define ERROR(uufsd, str) \ do { \ if ((uufsd) != NULL) \ (uufsd)->d_error = str; \ } while (0) #endif /* _LIBUFS_DEBUGGING */ #endif /* _LIBUFS */ /* * libufs structures. */ /* * userland ufs disk. */ struct uufsd { const char *d_name; /* disk name */ int d_ufs; /* decimal UFS version */ int d_fd; /* raw device file descriptor */ long d_bsize; /* device bsize */ ufs2_daddr_t d_sblock; /* superblock location */ caddr_t d_inoblock; /* inode block */ ino_t d_inomin; /* low inode */ ino_t d_inomax; /* high inode */ union { struct fs d_fs; /* filesystem information */ char d_sb[MAXBSIZE]; /* superblock as buffer */ } d_sbunion; union { struct cg d_cg; /* cylinder group */ char d_buf[MAXBSIZE]; /* cylinder group storage */ } d_cgunion; int d_ccg; /* current cylinder group */ int d_lcg; /* last cylinder group (in d_cg) */ const char *d_error; /* human readable disk error */ int d_mine; /* internal flags */ #define d_fs d_sbunion.d_fs #define d_sb d_sbunion.d_sb #define d_cg d_cgunion.d_cg }; __BEGIN_DECLS /* * libufs prototypes. */ /* * block.c */ ssize_t bread(struct uufsd *, ufs2_daddr_t, void *, size_t); ssize_t bwrite(struct uufsd *, ufs2_daddr_t, const void *, size_t); /* * cgroup.c */ int cgread(struct uufsd *); int cgread1(struct uufsd *, int); int cgwrite1(struct uufsd *, int); /* * inode.c */ int getino(struct uufsd *, void **, ino_t, int *); /* * sblock.c */ int sbread(struct uufsd *); int sbwrite(struct uufsd *, int); /* * type.c */ int ufs_disk_close(struct uufsd *); int ufs_disk_fillout(struct uufsd *, const char *); int ufs_disk_fillout_blank(struct uufsd *, const char *); int ufs_disk_write(struct uufsd *); __END_DECLS #endif /* __LIBUFS_H__ */ partclone-0.2.86/src/ufs/sys/000077500000000000000000000000001262102574200160015ustar00rootroot00000000000000partclone-0.2.86/src/ufs/sys/disklabel.h000066400000000000000000000241631262102574200201120ustar00rootroot00000000000000/*- * Copyright (c) 1987, 1988, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)disklabel.h 8.2 (Berkeley) 7/10/94 * $FreeBSD: src/sys/sys/disklabel.h,v 1.108.2.2.4.1 2009/04/15 03:14:26 kensmith Exp $ */ #ifndef _SYS_DISKLABEL_H_ #define _SYS_DISKLABEL_H_ #ifndef _KERNEL #include #endif #include #include /* * Disk description table, see disktab(5) */ #define _PATH_DISKTAB "/etc/disktab" /* * Each disk has a label which includes information about the hardware * disk geometry, filesystem partitions, and drive specific information. * The label is in block 0 or 1, possibly offset from the beginning * to leave room for a bootstrap, etc. */ /* XXX these should be defined per controller (or drive) elsewhere, not here! */ #if defined(__i386__) || defined(__amd64__) || defined(__arm__) || \ defined(__ia64__) #define LABELSECTOR 1 /* sector containing label */ #define LABELOFFSET 0 /* offset of label in sector */ #endif #define DISKMAGIC ((u_int32_t)0x82564557) /* The disk magic number */ #ifndef MAXPARTITIONS #define MAXPARTITIONS 8 #endif /* Size of bootblock area in sector-size neutral bytes */ #define BBSIZE 8192 #define LABEL_PART 2 /* partition containing label */ #define RAW_PART 2 /* partition containing whole disk */ #define SWAP_PART 1 /* partition normally containing swap */ struct disklabel { u_int32_t d_magic; /* the magic number */ u_int16_t d_type; /* drive type */ u_int16_t d_subtype; /* controller/d_type specific */ char d_typename[16]; /* type name, e.g. "eagle" */ char d_packname[16]; /* pack identifier */ /* disk geometry: */ u_int32_t d_secsize; /* # of bytes per sector */ u_int32_t d_nsectors; /* # of data sectors per track */ u_int32_t d_ntracks; /* # of tracks per cylinder */ u_int32_t d_ncylinders; /* # of data cylinders per unit */ u_int32_t d_secpercyl; /* # of data sectors per cylinder */ u_int32_t d_secperunit; /* # of data sectors per unit */ /* * Spares (bad sector replacements) below are not counted in * d_nsectors or d_secpercyl. Spare sectors are assumed to * be physical sectors which occupy space at the end of each * track and/or cylinder. */ u_int16_t d_sparespertrack; /* # of spare sectors per track */ u_int16_t d_sparespercyl; /* # of spare sectors per cylinder */ /* * Alternate cylinders include maintenance, replacement, configuration * description areas, etc. */ u_int32_t d_acylinders; /* # of alt. cylinders per unit */ /* hardware characteristics: */ /* * d_interleave, d_trackskew and d_cylskew describe perturbations * in the media format used to compensate for a slow controller. * Interleave is physical sector interleave, set up by the * formatter or controller when formatting. When interleaving is * in use, logically adjacent sectors are not physically * contiguous, but instead are separated by some number of * sectors. It is specified as the ratio of physical sectors * traversed per logical sector. Thus an interleave of 1:1 * implies contiguous layout, while 2:1 implies that logical * sector 0 is separated by one sector from logical sector 1. * d_trackskew is the offset of sector 0 on track N relative to * sector 0 on track N-1 on the same cylinder. Finally, d_cylskew * is the offset of sector 0 on cylinder N relative to sector 0 * on cylinder N-1. */ u_int16_t d_rpm; /* rotational speed */ u_int16_t d_interleave; /* hardware sector interleave */ u_int16_t d_trackskew; /* sector 0 skew, per track */ u_int16_t d_cylskew; /* sector 0 skew, per cylinder */ u_int32_t d_headswitch; /* head switch time, usec */ u_int32_t d_trkseek; /* track-to-track seek, usec */ u_int32_t d_flags; /* generic flags */ #define NDDATA 5 u_int32_t d_drivedata[NDDATA]; /* drive-type specific information */ #define NSPARE 5 u_int32_t d_spare[NSPARE]; /* reserved for future use */ u_int32_t d_magic2; /* the magic number (again) */ u_int16_t d_checksum; /* xor of data incl. partitions */ /* filesystem and partition information: */ u_int16_t d_npartitions; /* number of partitions in following */ u_int32_t d_bbsize; /* size of boot area at sn0, bytes */ u_int32_t d_sbsize; /* max size of fs superblock, bytes */ struct partition { /* the partition table */ u_int32_t p_size; /* number of sectors in partition */ u_int32_t p_offset; /* starting sector */ u_int32_t p_fsize; /* filesystem basic fragment size */ u_int8_t p_fstype; /* filesystem type, see below */ u_int8_t p_frag; /* filesystem fragments per block */ u_int16_t p_cpg; /* filesystem cylinders per group */ } d_partitions[MAXPARTITIONS]; /* actually may be more */ }; #ifdef CTASSERT CTASSERT(sizeof(struct disklabel) == 148 + MAXPARTITIONS * 16); #endif static __inline u_int16_t dkcksum(struct disklabel *lp); static __inline u_int16_t dkcksum(struct disklabel *lp) { u_int16_t *start, *end; u_int16_t sum = 0; start = (u_int16_t *)lp; end = (u_int16_t *)&lp->d_partitions[lp->d_npartitions]; while (start < end) sum ^= *start++; return (sum); } /* d_type values: */ #define DTYPE_SMD 1 /* SMD, XSMD; VAX hp/up */ #define DTYPE_MSCP 2 /* MSCP */ #define DTYPE_DEC 3 /* other DEC (rk, rl) */ #define DTYPE_SCSI 4 /* SCSI */ #define DTYPE_ESDI 5 /* ESDI interface */ #define DTYPE_ST506 6 /* ST506 etc. */ #define DTYPE_HPIB 7 /* CS/80 on HP-IB */ #define DTYPE_HPFL 8 /* HP Fiber-link */ #define DTYPE_FLOPPY 10 /* floppy */ #define DTYPE_CCD 11 /* concatenated disk */ #define DTYPE_VINUM 12 /* vinum volume */ #define DTYPE_DOC2K 13 /* Msys DiskOnChip */ #define DTYPE_RAID 14 /* CMU RAIDFrame */ #define DTYPE_JFS2 16 /* IBM JFS 2 */ #ifdef DKTYPENAMES static const char *dktypenames[] = { "unknown", "SMD", "MSCP", "old DEC", "SCSI", "ESDI", "ST506", "HP-IB", "HP-FL", "type 9", "floppy", "CCD", "Vinum", "DOC2K", "Raid", "?", "jfs", NULL }; #define DKMAXTYPES (sizeof(dktypenames) / sizeof(dktypenames[0]) - 1) #endif /* * Filesystem type and version. * Used to interpret other filesystem-specific * per-partition information. */ #define FS_UNUSED 0 /* unused */ #define FS_SWAP 1 /* swap */ #define FS_V6 2 /* Sixth Edition */ #define FS_V7 3 /* Seventh Edition */ #define FS_SYSV 4 /* System V */ #define FS_V71K 5 /* V7 with 1K blocks (4.1, 2.9) */ #define FS_V8 6 /* Eighth Edition, 4K blocks */ #define FS_BSDFFS 7 /* 4.2BSD fast filesystem */ #define FS_MSDOS 8 /* MSDOS filesystem */ #define FS_BSDLFS 9 /* 4.4BSD log-structured filesystem */ #define FS_OTHER 10 /* in use, but unknown/unsupported */ #define FS_HPFS 11 /* OS/2 high-performance filesystem */ #define FS_ISO9660 12 /* ISO 9660, normally CD-ROM */ #define FS_BOOT 13 /* partition contains bootstrap */ #define FS_VINUM 14 /* Vinum drive */ #define FS_RAID 15 /* RAIDFrame drive */ #define FS_FILECORE 16 /* Acorn Filecore Filing System */ #define FS_EXT2FS 17 /* ext2fs */ #define FS_NTFS 18 /* Windows/NT file system */ #define FS_CCD 20 /* concatenated disk component */ #define FS_JFS2 21 /* IBM JFS2 */ #define FS_UDF 24 /* UDF */ #define FS_EFS 26 /* SGI's Extent File system */ #define FS_ZFS 27 /* Sun's ZFS */ #ifdef FSTYPENAMES static const char *fstypenames[] = { "unused", "swap", "Version 6", "Version 7", "System V", "4.1BSD", "Eighth Edition", "4.2BSD", "MSDOS", "4.4LFS", "unknown", "HPFS", "ISO9660", "boot", "vinum", "raid", "Filecore", "EXT2FS", "NTFS", "?", "ccd", "jfs", "?", "?", "UDF", "?", "EFS", "ZFS", NULL }; #define FSMAXTYPES (sizeof(fstypenames) / sizeof(fstypenames[0]) - 1) #endif /* * flags shared by various drives: */ #define D_REMOVABLE 0x01 /* removable media */ #define D_ECC 0x02 /* supports ECC */ #define D_BADSECT 0x04 /* supports bad sector forw. */ #define D_RAMDISK 0x08 /* disk emulator */ #define D_CHAIN 0x10 /* can do back-back transfers */ /* * Disklabel-specific ioctls. * * NB: defines ioctls from 'd'/128 and up. */ /* get and set disklabel */ #define DIOCGDINFO _IOR('d', 101, struct disklabel)/* get */ #define DIOCSDINFO _IOW('d', 102, struct disklabel)/* set */ #define DIOCWDINFO _IOW('d', 103, struct disklabel)/* set, update disk */ #define DIOCBSDBB _IOW('d', 110, void *) /* write bootblocks */ /* * Functions for proper encoding/decoding of struct disklabel into/from * bytestring. */ void bsd_partition_le_dec(u_char *ptr, struct partition *d); int bsd_disklabel_le_dec(u_char *ptr, struct disklabel *d, int maxpart); void bsd_partition_le_enc(u_char *ptr, struct partition *d); void bsd_disklabel_le_enc(u_char *ptr, struct disklabel *d); #ifndef _KERNEL __BEGIN_DECLS struct disklabel *getdiskbyname(const char *); __END_DECLS #endif #endif /* !_SYS_DISKLABEL_H_ */ partclone-0.2.86/src/ufs/ufs/000077500000000000000000000000001262102574200157605ustar00rootroot00000000000000partclone-0.2.86/src/ufs/ufs/dinode.h000066400000000000000000000206371262102574200174030ustar00rootroot00000000000000/*- * Copyright (c) 2002 Networks Associates Technology, Inc. * All rights reserved. * * This software was developed for the FreeBSD Project by Marshall * Kirk McKusick and Network Associates Laboratories, the Security * Research Division of Network Associates, Inc. under DARPA/SPAWAR * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS * research program * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * Copyright (c) 1982, 1989, 1993 * The Regents of the University of California. All rights reserved. * (c) UNIX System Laboratories, Inc. * All or some portions of this file are derived from material licensed * to the University of California by American Telephone and Telegraph * Co. or Unix System Laboratories, Inc. and are reproduced herein with * the permission of UNIX System Laboratories, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The names of the authors may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)dinode.h 8.3 (Berkeley) 1/21/94 * $FreeBSD: src/sys/ufs/ufs/dinode.h,v 1.17.8.1 2009/04/15 03:14:26 kensmith Exp $ */ #ifndef _UFS_UFS_DINODE_H_ #define _UFS_UFS_DINODE_H_ #include /* * The root inode is the root of the filesystem. Inode 0 can't be used for * normal purposes and historically bad blocks were linked to inode 1, thus * the root inode is 2. (Inode 1 is no longer used for this purpose, however * numerous dump tapes make this assumption, so we are stuck with it). */ #define ROOTINO ((ino_t)2) /* * The Whiteout inode# is a dummy non-zero inode number which will * never be allocated to a real file. It is used as a place holder * in the directory entry which has been tagged as a DT_WHT entry. * See the comments about ROOTINO above. */ #define WINO ((ino_t)1) /* * The size of physical and logical block numbers and time fields in UFS. */ typedef int32_t ufs1_daddr_t; typedef int64_t ufs2_daddr_t; typedef int64_t ufs_lbn_t; typedef int64_t ufs_time_t; /* File permissions. */ #define IEXEC 0000100 /* Executable. */ #define IWRITE 0000200 /* Writeable. */ #define IREAD 0000400 /* Readable. */ #define ISVTX 0001000 /* Sticky bit. */ #define ISGID 0002000 /* Set-gid. */ #define ISUID 0004000 /* Set-uid. */ /* File types. */ #define IFMT 0170000 /* Mask of file type. */ #define IFIFO 0010000 /* Named pipe (fifo). */ #define IFCHR 0020000 /* Character device. */ #define IFDIR 0040000 /* Directory file. */ #define IFBLK 0060000 /* Block device. */ #define IFREG 0100000 /* Regular file. */ #define IFLNK 0120000 /* Symbolic link. */ #define IFSOCK 0140000 /* UNIX domain socket. */ #define IFWHT 0160000 /* Whiteout. */ /* * A dinode contains all the meta-data associated with a UFS2 file. * This structure defines the on-disk format of a dinode. Since * this structure describes an on-disk structure, all its fields * are defined by types with precise widths. */ #define NXADDR 2 /* External addresses in inode. */ #define NDADDR 12 /* Direct addresses in inode. */ #define NIADDR 3 /* Indirect addresses in inode. */ struct ufs2_dinode { u_int16_t di_mode; /* 0: IFMT, permissions; see below. */ int16_t di_nlink; /* 2: File link count. */ u_int32_t di_uid; /* 4: File owner. */ u_int32_t di_gid; /* 8: File group. */ u_int32_t di_blksize; /* 12: Inode blocksize. */ u_int64_t di_size; /* 16: File byte count. */ u_int64_t di_blocks; /* 24: Blocks actually held. */ ufs_time_t di_atime; /* 32: Last access time. */ ufs_time_t di_mtime; /* 40: Last modified time. */ ufs_time_t di_ctime; /* 48: Last inode change time. */ ufs_time_t di_birthtime; /* 56: Inode creation time. */ int32_t di_mtimensec; /* 64: Last modified time. */ int32_t di_atimensec; /* 68: Last access time. */ int32_t di_ctimensec; /* 72: Last inode change time. */ int32_t di_birthnsec; /* 76: Inode creation time. */ int32_t di_gen; /* 80: Generation number. */ u_int32_t di_kernflags; /* 84: Kernel flags. */ u_int32_t di_flags; /* 88: Status flags (chflags). */ int32_t di_extsize; /* 92: External attributes block. */ ufs2_daddr_t di_extb[NXADDR];/* 96: External attributes block. */ ufs2_daddr_t di_db[NDADDR]; /* 112: Direct disk blocks. */ ufs2_daddr_t di_ib[NIADDR]; /* 208: Indirect disk blocks. */ int64_t di_spare[3]; /* 232: Reserved; currently unused */ }; /* * The di_db fields may be overlaid with other information for * file types that do not have associated disk storage. Block * and character devices overlay the first data block with their * dev_t value. Short symbolic links place their path in the * di_db area. */ #define di_rdev di_db[0] /* * A UFS1 dinode contains all the meta-data associated with a UFS1 file. * This structure defines the on-disk format of a UFS1 dinode. Since * this structure describes an on-disk structure, all its fields * are defined by types with precise widths. */ struct ufs1_dinode { u_int16_t di_mode; /* 0: IFMT, permissions; see below. */ int16_t di_nlink; /* 2: File link count. */ union { u_int16_t oldids[2]; /* 4: Ffs: old user and group ids. */ } di_u; u_int64_t di_size; /* 8: File byte count. */ int32_t di_atime; /* 16: Last access time. */ int32_t di_atimensec; /* 20: Last access time. */ int32_t di_mtime; /* 24: Last modified time. */ int32_t di_mtimensec; /* 28: Last modified time. */ int32_t di_ctime; /* 32: Last inode change time. */ int32_t di_ctimensec; /* 36: Last inode change time. */ ufs1_daddr_t di_db[NDADDR]; /* 40: Direct disk blocks. */ ufs1_daddr_t di_ib[NIADDR]; /* 88: Indirect disk blocks. */ u_int32_t di_flags; /* 100: Status flags (chflags). */ int32_t di_blocks; /* 104: Blocks actually held. */ int32_t di_gen; /* 108: Generation number. */ u_int32_t di_uid; /* 112: File owner. */ u_int32_t di_gid; /* 116: File group. */ int32_t di_spare[2]; /* 120: Reserved; currently unused */ }; #define di_ogid di_u.oldids[1] #define di_ouid di_u.oldids[0] #endif /* _UFS_UFS_DINODE_H_ */ partclone-0.2.86/src/ufs/ufs/fs.h000066400000000000000000000645671262102574200165630ustar00rootroot00000000000000/*- * Copyright (c) 1982, 1986, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)fs.h 8.13 (Berkeley) 3/21/95 * $FreeBSD: src/sys/ufs/ffs/fs.h,v 1.49.8.1 2009/04/15 03:14:26 kensmith Exp $ */ #ifndef _UFS_FFS_FS_H_ #define _UFS_FFS_FS_H_ #include #include /* * Each disk drive contains some number of filesystems. * A filesystem consists of a number of cylinder groups. * Each cylinder group has inodes and data. * * A filesystem is described by its super-block, which in turn * describes the cylinder groups. The super-block is critical * data and is replicated in each cylinder group to protect against * catastrophic loss. This is done at `newfs' time and the critical * super-block data does not change, so the copies need not be * referenced further unless disaster strikes. * * For filesystem fs, the offsets of the various blocks of interest * are given in the super block as: * [fs->fs_sblkno] Super-block * [fs->fs_cblkno] Cylinder group block * [fs->fs_iblkno] Inode blocks * [fs->fs_dblkno] Data blocks * The beginning of cylinder group cg in fs, is given by * the ``cgbase(fs, cg)'' macro. * * Depending on the architecture and the media, the superblock may * reside in any one of four places. For tiny media where every block * counts, it is placed at the very front of the partition. Historically, * UFS1 placed it 8K from the front to leave room for the disk label and * a small bootstrap. For UFS2 it got moved to 64K from the front to leave * room for the disk label and a bigger bootstrap, and for really piggy * systems we check at 256K from the front if the first three fail. In * all cases the size of the superblock will be SBLOCKSIZE. All values are * given in byte-offset form, so they do not imply a sector size. The * SBLOCKSEARCH specifies the order in which the locations should be searched. */ #define SBLOCK_FLOPPY 0 #define SBLOCK_UFS1 8192 #define SBLOCK_UFS2 65536 #define SBLOCK_PIGGY 262144 #define SBLOCKSIZE 8192 #define SBLOCKSEARCH \ { SBLOCK_UFS2, SBLOCK_UFS1, SBLOCK_FLOPPY, SBLOCK_PIGGY, -1 } /* * Max number of fragments per block. This value is NOT tweakable. */ #define MAXFRAG 8 /* * Addresses stored in inodes are capable of addressing fragments * of `blocks'. File system blocks of at most size MAXBSIZE can * be optionally broken into 2, 4, or 8 pieces, each of which is * addressable; these pieces may be DEV_BSIZE, or some multiple of * a DEV_BSIZE unit. * * Large files consist of exclusively large data blocks. To avoid * undue wasted disk space, the last data block of a small file may be * allocated as only as many fragments of a large block as are * necessary. The filesystem format retains only a single pointer * to such a fragment, which is a piece of a single large block that * has been divided. The size of such a fragment is determinable from * information in the inode, using the ``blksize(fs, ip, lbn)'' macro. * * The filesystem records space availability at the fragment level; * to determine block availability, aligned fragments are examined. */ /* * MINBSIZE is the smallest allowable block size. * In order to insure that it is possible to create files of size * 2^32 with only two levels of indirection, MINBSIZE is set to 4096. * MINBSIZE must be big enough to hold a cylinder group block, * thus changes to (struct cg) must keep its size within MINBSIZE. * Note that super blocks are always of size SBSIZE, * and that both SBSIZE and MAXBSIZE must be >= MINBSIZE. */ #define MINBSIZE 4096 /* * The path name on which the filesystem is mounted is maintained * in fs_fsmnt. MAXMNTLEN defines the amount of space allocated in * the super block for this name. */ #define MAXMNTLEN 468 /* * The volume name for this filesystem is maintained in fs_volname. * MAXVOLLEN defines the length of the buffer allocated. */ #define MAXVOLLEN 32 /* * There is a 128-byte region in the superblock reserved for in-core * pointers to summary information. Originally this included an array * of pointers to blocks of struct csum; now there are just a few * pointers and the remaining space is padded with fs_ocsp[]. * * NOCSPTRS determines the size of this padding. One pointer (fs_csp) * is taken away to point to a contiguous array of struct csum for * all cylinder groups; a second (fs_maxcluster) points to an array * of cluster sizes that is computed as cylinder groups are inspected, * and the third points to an array that tracks the creation of new * directories. A fourth pointer, fs_active, is used when creating * snapshots; it points to a bitmap of cylinder groups for which the * free-block bitmap has changed since the snapshot operation began. */ #define NOCSPTRS ((128 / sizeof(void *)) - 4) /* * A summary of contiguous blocks of various sizes is maintained * in each cylinder group. Normally this is set by the initial * value of fs_maxcontig. To conserve space, a maximum summary size * is set by FS_MAXCONTIG. */ #define FS_MAXCONTIG 16 /* * MINFREE gives the minimum acceptable percentage of filesystem * blocks which may be free. If the freelist drops below this level * only the superuser may continue to allocate blocks. This may * be set to 0 if no reserve of free blocks is deemed necessary, * however throughput drops by fifty percent if the filesystem * is run at between 95% and 100% full; thus the minimum default * value of fs_minfree is 5%. However, to get good clustering * performance, 10% is a better choice. hence we use 10% as our * default value. With 10% free space, fragmentation is not a * problem, so we choose to optimize for time. */ #define MINFREE 8 #define DEFAULTOPT FS_OPTTIME /* * Grigoriy Orlov has done some extensive work to fine * tune the layout preferences for directories within a filesystem. * His algorithm can be tuned by adjusting the following parameters * which tell the system the average file size and the average number * of files per directory. These defaults are well selected for typical * filesystems, but may need to be tuned for odd cases like filesystems * being used for squid caches or news spools. */ #define AVFILESIZ 16384 /* expected average file size */ #define AFPDIR 64 /* expected number of files per directory */ /* * The maximum number of snapshot nodes that can be associated * with each filesystem. This limit affects only the number of * snapshot files that can be recorded within the superblock so * that they can be found when the filesystem is mounted. However, * maintaining too many will slow the filesystem performance, so * having this limit is a good idea. */ #define FSMAXSNAP 20 /* * Used to identify special blocks in snapshots: * * BLK_NOCOPY - A block that was unallocated at the time the snapshot * was taken, hence does not need to be copied when written. * BLK_SNAP - A block held by another snapshot that is not needed by this * snapshot. When the other snapshot is freed, the BLK_SNAP entries * are converted to BLK_NOCOPY. These are needed to allow fsck to * identify blocks that are in use by other snapshots (which are * expunged from this snapshot). */ #define BLK_NOCOPY ((ufs2_daddr_t)(1)) #define BLK_SNAP ((ufs2_daddr_t)(2)) /* * Sysctl values for the fast filesystem. */ #define FFS_ADJ_REFCNT 1 /* adjust inode reference count */ #define FFS_ADJ_BLKCNT 2 /* adjust inode used block count */ #define FFS_BLK_FREE 3 /* free range of blocks in map */ #define FFS_DIR_FREE 4 /* free specified dir inodes in map */ #define FFS_FILE_FREE 5 /* free specified file inodes in map */ #define FFS_SET_FLAGS 6 /* set filesystem flags */ #define FFS_ADJ_NDIR 7 /* adjust number of directories */ #define FFS_ADJ_NBFREE 8 /* adjust number of free blocks */ #define FFS_ADJ_NIFREE 9 /* adjust number of free inodes */ #define FFS_ADJ_NFFREE 10 /* adjust number of free frags */ #define FFS_ADJ_NUMCLUSTERS 11 /* adjust number of free clusters */ #define FFS_MAXID 12 /* number of valid ffs ids */ /* * Command structure passed in to the filesystem to adjust filesystem values. */ #define FFS_CMD_VERSION 0x19790518 /* version ID */ struct fsck_cmd { int32_t version; /* version of command structure */ int32_t handle; /* reference to filesystem to be changed */ int64_t value; /* inode or block number to be affected */ int64_t size; /* amount or range to be adjusted */ int64_t spare; /* reserved for future use */ }; /* * Per cylinder group information; summarized in blocks allocated * from first cylinder group data blocks. These blocks have to be * read in from fs_csaddr (size fs_cssize) in addition to the * super block. */ struct csum { int32_t cs_ndir; /* number of directories */ int32_t cs_nbfree; /* number of free blocks */ int32_t cs_nifree; /* number of free inodes */ int32_t cs_nffree; /* number of free frags */ }; struct csum_total { int64_t cs_ndir; /* number of directories */ int64_t cs_nbfree; /* number of free blocks */ int64_t cs_nifree; /* number of free inodes */ int64_t cs_nffree; /* number of free frags */ int64_t cs_numclusters; /* number of free clusters */ int64_t cs_spare[3]; /* future expansion */ }; /* * Super block for an FFS filesystem. */ struct fs { int32_t fs_firstfield; /* historic filesystem linked list, */ int32_t fs_unused_1; /* used for incore super blocks */ int32_t fs_sblkno; /* offset of super-block in filesys */ int32_t fs_cblkno; /* offset of cyl-block in filesys */ int32_t fs_iblkno; /* offset of inode-blocks in filesys */ int32_t fs_dblkno; /* offset of first data after cg */ int32_t fs_old_cgoffset; /* cylinder group offset in cylinder */ int32_t fs_old_cgmask; /* used to calc mod fs_ntrak */ int32_t fs_old_time; /* last time written */ int32_t fs_old_size; /* number of blocks in fs */ int32_t fs_old_dsize; /* number of data blocks in fs */ int32_t fs_ncg; /* number of cylinder groups */ int32_t fs_bsize; /* size of basic blocks in fs */ int32_t fs_fsize; /* size of frag blocks in fs */ int32_t fs_frag; /* number of frags in a block in fs */ /* these are configuration parameters */ int32_t fs_minfree; /* minimum percentage of free blocks */ int32_t fs_old_rotdelay; /* num of ms for optimal next block */ int32_t fs_old_rps; /* disk revolutions per second */ /* these fields can be computed from the others */ int32_t fs_bmask; /* ``blkoff'' calc of blk offsets */ int32_t fs_fmask; /* ``fragoff'' calc of frag offsets */ int32_t fs_bshift; /* ``lblkno'' calc of logical blkno */ int32_t fs_fshift; /* ``numfrags'' calc number of frags */ /* these are configuration parameters */ int32_t fs_maxcontig; /* max number of contiguous blks */ int32_t fs_maxbpg; /* max number of blks per cyl group */ /* these fields can be computed from the others */ int32_t fs_fragshift; /* block to frag shift */ int32_t fs_fsbtodb; /* fsbtodb and dbtofsb shift constant */ int32_t fs_sbsize; /* actual size of super block */ int32_t fs_spare1[2]; /* old fs_csmask */ /* old fs_csshift */ int32_t fs_nindir; /* value of NINDIR */ int32_t fs_inopb; /* value of INOPB */ int32_t fs_old_nspf; /* value of NSPF */ /* yet another configuration parameter */ int32_t fs_optim; /* optimization preference, see below */ int32_t fs_old_npsect; /* # sectors/track including spares */ int32_t fs_old_interleave; /* hardware sector interleave */ int32_t fs_old_trackskew; /* sector 0 skew, per track */ int32_t fs_id[2]; /* unique filesystem id */ /* sizes determined by number of cylinder groups and their sizes */ int32_t fs_old_csaddr; /* blk addr of cyl grp summary area */ int32_t fs_cssize; /* size of cyl grp summary area */ int32_t fs_cgsize; /* cylinder group size */ int32_t fs_spare2; /* old fs_ntrak */ int32_t fs_old_nsect; /* sectors per track */ int32_t fs_old_spc; /* sectors per cylinder */ int32_t fs_old_ncyl; /* cylinders in filesystem */ int32_t fs_old_cpg; /* cylinders per group */ int32_t fs_ipg; /* inodes per group */ int32_t fs_fpg; /* blocks per group * fs_frag */ /* this data must be re-computed after crashes */ struct csum fs_old_cstotal; /* cylinder summary information */ /* these fields are cleared at mount time */ int8_t fs_fmod; /* super block modified flag */ int8_t fs_clean; /* filesystem is clean flag */ int8_t fs_ronly; /* mounted read-only flag */ int8_t fs_old_flags; /* old FS_ flags */ u_char fs_fsmnt[MAXMNTLEN]; /* name mounted on */ u_char fs_volname[MAXVOLLEN]; /* volume name */ u_int64_t fs_swuid; /* system-wide uid */ int32_t fs_pad; /* due to alignment of fs_swuid */ /* these fields retain the current block allocation info */ int32_t fs_cgrotor; /* last cg searched */ void *fs_ocsp[NOCSPTRS]; /* padding; was list of fs_cs buffers */ u_int8_t *fs_contigdirs; /* (u) # of contig. allocated dirs */ struct csum *fs_csp; /* (u) cg summary info buffer */ int32_t *fs_maxcluster; /* (u) max cluster in each cyl group */ u_int *fs_active; /* (u) used by snapshots to track fs */ int32_t fs_old_cpc; /* cyl per cycle in postbl */ int32_t fs_maxbsize; /* maximum blocking factor permitted */ int64_t fs_unrefs; /* number of unreferenced inodes */ int64_t fs_sparecon64[16]; /* old rotation block list head */ int64_t fs_sblockloc; /* byte offset of standard superblock */ struct csum_total fs_cstotal; /* (u) cylinder summary information */ ufs_time_t fs_time; /* last time written */ int64_t fs_size; /* number of blocks in fs */ int64_t fs_dsize; /* number of data blocks in fs */ ufs2_daddr_t fs_csaddr; /* blk addr of cyl grp summary area */ int64_t fs_pendingblocks; /* (u) blocks being freed */ int32_t fs_pendinginodes; /* (u) inodes being freed */ int32_t fs_snapinum[FSMAXSNAP];/* list of snapshot inode numbers */ int32_t fs_avgfilesize; /* expected average file size */ int32_t fs_avgfpdir; /* expected # of files per directory */ int32_t fs_save_cgsize; /* save real cg size to use fs_bsize */ int32_t fs_sparecon32[26]; /* reserved for future constants */ int32_t fs_flags; /* see FS_ flags below */ int32_t fs_contigsumsize; /* size of cluster summary array */ int32_t fs_maxsymlinklen; /* max length of an internal symlink */ int32_t fs_old_inodefmt; /* format of on-disk inodes */ u_int64_t fs_maxfilesize; /* maximum representable file size */ int64_t fs_qbmask; /* ~fs_bmask for use with 64-bit size */ int64_t fs_qfmask; /* ~fs_fmask for use with 64-bit size */ int32_t fs_state; /* validate fs_clean field */ int32_t fs_old_postblformat; /* format of positional layout tables */ int32_t fs_old_nrpos; /* number of rotational positions */ int32_t fs_spare5[2]; /* old fs_postbloff */ /* old fs_rotbloff */ int32_t fs_magic; /* magic number */ }; /* Sanity checking. */ #ifdef CTASSERT CTASSERT(sizeof(struct fs) == 1376); #endif /* * Filesystem identification */ #define FS_UFS1_MAGIC 0x011954 /* UFS1 fast filesystem magic number */ #define FS_UFS2_MAGIC 0x19540119 /* UFS2 fast filesystem magic number */ #define FS_BAD_MAGIC 0x19960408 /* UFS incomplete newfs magic number */ #define FS_OKAY 0x7c269d38 /* superblock checksum */ #define FS_42INODEFMT -1 /* 4.2BSD inode format */ #define FS_44INODEFMT 2 /* 4.4BSD inode format */ /* * Preference for optimization. */ #define FS_OPTTIME 0 /* minimize allocation time */ #define FS_OPTSPACE 1 /* minimize disk fragmentation */ /* * Filesystem flags. * * The FS_UNCLEAN flag is set by the kernel when the filesystem was * mounted with fs_clean set to zero. The FS_DOSOFTDEP flag indicates * that the filesystem should be managed by the soft updates code. * Note that the FS_NEEDSFSCK flag is set and cleared only by the * fsck utility. It is set when background fsck finds an unexpected * inconsistency which requires a traditional foreground fsck to be * run. Such inconsistencies should only be found after an uncorrectable * disk error. A foreground fsck will clear the FS_NEEDSFSCK flag when * it has successfully cleaned up the filesystem. The kernel uses this * flag to enforce that inconsistent filesystems be mounted read-only. * The FS_INDEXDIRS flag when set indicates that the kernel maintains * on-disk auxiliary indexes (such as B-trees) for speeding directory * accesses. Kernels that do not support auxiliary indicies clear the * flag to indicate that the indicies need to be rebuilt (by fsck) before * they can be used. * * FS_ACLS indicates that ACLs are administratively enabled for the * file system, so they should be loaded from extended attributes, * observed for access control purposes, and be administered by object * owners. FS_MULTILABEL indicates that the TrustedBSD MAC Framework * should attempt to back MAC labels into extended attributes on the * file system rather than maintain a single mount label for all * objects. */ #define FS_UNCLEAN 0x01 /* filesystem not clean at mount */ #define FS_DOSOFTDEP 0x02 /* filesystem using soft dependencies */ #define FS_NEEDSFSCK 0x04 /* filesystem needs sync fsck before mount */ #define FS_INDEXDIRS 0x08 /* kernel supports indexed directories */ #define FS_ACLS 0x10 /* file system has ACLs enabled */ #define FS_MULTILABEL 0x20 /* file system is MAC multi-label */ #define FS_GJOURNAL 0x40 /* gjournaled file system */ #define FS_FLAGS_UPDATED 0x80 /* flags have been moved to new location */ /* * Macros to access bits in the fs_active array. */ #define ACTIVECGNUM(fs, cg) ((fs)->fs_active[(cg) / (NBBY * sizeof(int))]) #define ACTIVECGOFF(cg) (1 << ((cg) % (NBBY * sizeof(int)))) #define ACTIVESET(fs, cg) do { \ if ((fs)->fs_active) \ ACTIVECGNUM((fs), (cg)) |= ACTIVECGOFF((cg)); \ } while (0) #define ACTIVECLEAR(fs, cg) do { \ if ((fs)->fs_active) \ ACTIVECGNUM((fs), (cg)) &= ~ACTIVECGOFF((cg)); \ } while (0) /* * The size of a cylinder group is calculated by CGSIZE. The maximum size * is limited by the fact that cylinder groups are at most one block. * Its size is derived from the size of the maps maintained in the * cylinder group and the (struct cg) size. */ #define CGSIZE(fs) \ /* base cg */ (sizeof(struct cg) + sizeof(int32_t) + \ /* old btotoff */ (fs)->fs_old_cpg * sizeof(int32_t) + \ /* old boff */ (fs)->fs_old_cpg * sizeof(u_int16_t) + \ /* inode map */ howmany((fs)->fs_ipg, NBBY) + \ /* block map */ howmany((fs)->fs_fpg, NBBY) +\ /* if present */ ((fs)->fs_contigsumsize <= 0 ? 0 : \ /* cluster sum */ (fs)->fs_contigsumsize * sizeof(int32_t) + \ /* cluster map */ howmany(fragstoblks(fs, (fs)->fs_fpg), NBBY))) /* * The minimal number of cylinder groups that should be created. */ #define MINCYLGRPS 4 /* * Convert cylinder group to base address of its global summary info. */ #define fs_cs(fs, indx) fs_csp[indx] /* * Cylinder group block for a filesystem. */ #define CG_MAGIC 0x090255 struct cg { int32_t cg_firstfield; /* historic cyl groups linked list */ int32_t cg_magic; /* magic number */ int32_t cg_old_time; /* time last written */ int32_t cg_cgx; /* we are the cgx'th cylinder group */ int16_t cg_old_ncyl; /* number of cyl's this cg */ int16_t cg_old_niblk; /* number of inode blocks this cg */ int32_t cg_ndblk; /* number of data blocks this cg */ struct csum cg_cs; /* cylinder summary information */ int32_t cg_rotor; /* position of last used block */ int32_t cg_frotor; /* position of last used frag */ int32_t cg_irotor; /* position of last used inode */ int32_t cg_frsum[MAXFRAG]; /* counts of available frags */ int32_t cg_old_btotoff; /* (int32) block totals per cylinder */ int32_t cg_old_boff; /* (u_int16) free block positions */ int32_t cg_iusedoff; /* (u_int8) used inode map */ int32_t cg_freeoff; /* (u_int8) free block map */ int32_t cg_nextfreeoff; /* (u_int8) next available space */ int32_t cg_clustersumoff; /* (u_int32) counts of avail clusters */ int32_t cg_clusteroff; /* (u_int8) free cluster map */ int32_t cg_nclusterblks; /* number of clusters this cg */ int32_t cg_niblk; /* number of inode blocks this cg */ int32_t cg_initediblk; /* last initialized inode */ int32_t cg_unrefs; /* number of unreferenced inodes */ int32_t cg_sparecon32[2]; /* reserved for future use */ ufs_time_t cg_time; /* time last written */ int64_t cg_sparecon64[3]; /* reserved for future use */ u_int8_t cg_space[1]; /* space for cylinder group maps */ /* actually longer */ }; /* * Macros for access to cylinder group array structures */ #define cg_chkmagic(cgp) ((cgp)->cg_magic == CG_MAGIC) #define cg_inosused(cgp) \ ((u_int8_t *)((u_int8_t *)(cgp) + (cgp)->cg_iusedoff)) #define cg_blksfree(cgp) \ ((u_int8_t *)((u_int8_t *)(cgp) + (cgp)->cg_freeoff)) #define cg_clustersfree(cgp) \ ((u_int8_t *)((u_int8_t *)(cgp) + (cgp)->cg_clusteroff)) #define cg_clustersum(cgp) \ ((int32_t *)((uintptr_t)(cgp) + (cgp)->cg_clustersumoff)) /* * Turn filesystem block numbers into disk block addresses. * This maps filesystem blocks to device size blocks. */ #define fsbtodb(fs, b) ((daddr_t)(b) << (fs)->fs_fsbtodb) #define dbtofsb(fs, b) ((b) >> (fs)->fs_fsbtodb) /* * Cylinder group macros to locate things in cylinder groups. * They calc filesystem addresses of cylinder group data structures. */ #define cgbase(fs, c) (((ufs2_daddr_t)(fs)->fs_fpg) * (c)) #define cgdmin(fs, c) (cgstart(fs, c) + (fs)->fs_dblkno) /* 1st data */ #define cgimin(fs, c) (cgstart(fs, c) + (fs)->fs_iblkno) /* inode blk */ #define cgsblock(fs, c) (cgstart(fs, c) + (fs)->fs_sblkno) /* super blk */ #define cgtod(fs, c) (cgstart(fs, c) + (fs)->fs_cblkno) /* cg block */ #define cgstart(fs, c) \ ((fs)->fs_magic == FS_UFS2_MAGIC ? cgbase(fs, c) : \ (cgbase(fs, c) + (fs)->fs_old_cgoffset * ((c) & ~((fs)->fs_old_cgmask)))) /* * Macros for handling inode numbers: * inode number to filesystem block offset. * inode number to cylinder group number. * inode number to filesystem block address. */ #define ino_to_cg(fs, x) ((x) / (fs)->fs_ipg) #define ino_to_fsba(fs, x) \ ((ufs2_daddr_t)(cgimin(fs, ino_to_cg(fs, x)) + \ (blkstofrags((fs), (((x) % (fs)->fs_ipg) / INOPB(fs)))))) #define ino_to_fsbo(fs, x) ((x) % INOPB(fs)) /* * Give cylinder group number for a filesystem block. * Give cylinder group block number for a filesystem block. */ #define dtog(fs, d) ((d) / (fs)->fs_fpg) #define dtogd(fs, d) ((d) % (fs)->fs_fpg) /* * Extract the bits for a block from a map. * Compute the cylinder and rotational position of a cyl block addr. */ #define blkmap(fs, map, loc) \ (((map)[(loc) / NBBY] >> ((loc) % NBBY)) & (0xff >> (NBBY - (fs)->fs_frag))) /* * The following macros optimize certain frequently calculated * quantities by using shifts and masks in place of divisions * modulos and multiplications. */ #define blkoff(fs, loc) /* calculates (loc % fs->fs_bsize) */ \ ((loc) & (fs)->fs_qbmask) #define fragoff(fs, loc) /* calculates (loc % fs->fs_fsize) */ \ ((loc) & (fs)->fs_qfmask) #define lfragtosize(fs, frag) /* calculates ((off_t)frag * fs->fs_fsize) */ \ (((off_t)(frag)) << (fs)->fs_fshift) #define lblktosize(fs, blk) /* calculates ((off_t)blk * fs->fs_bsize) */ \ (((off_t)(blk)) << (fs)->fs_bshift) /* Use this only when `blk' is known to be small, e.g., < NDADDR. */ #define smalllblktosize(fs, blk) /* calculates (blk * fs->fs_bsize) */ \ ((blk) << (fs)->fs_bshift) #define lblkno(fs, loc) /* calculates (loc / fs->fs_bsize) */ \ ((loc) >> (fs)->fs_bshift) #define numfrags(fs, loc) /* calculates (loc / fs->fs_fsize) */ \ ((loc) >> (fs)->fs_fshift) #define blkroundup(fs, size) /* calculates roundup(size, fs->fs_bsize) */ \ (((size) + (fs)->fs_qbmask) & (fs)->fs_bmask) #define fragroundup(fs, size) /* calculates roundup(size, fs->fs_fsize) */ \ (((size) + (fs)->fs_qfmask) & (fs)->fs_fmask) #define fragstoblks(fs, frags) /* calculates (frags / fs->fs_frag) */ \ ((frags) >> (fs)->fs_fragshift) #define blkstofrags(fs, blks) /* calculates (blks * fs->fs_frag) */ \ ((blks) << (fs)->fs_fragshift) #define fragnum(fs, fsb) /* calculates (fsb % fs->fs_frag) */ \ ((fsb) & ((fs)->fs_frag - 1)) #define blknum(fs, fsb) /* calculates rounddown(fsb, fs->fs_frag) */ \ ((fsb) &~ ((fs)->fs_frag - 1)) /* * Determine the number of available frags given a * percentage to hold in reserve. */ #define freespace(fs, percentreserved) \ (blkstofrags((fs), (fs)->fs_cstotal.cs_nbfree) + \ (fs)->fs_cstotal.cs_nffree - \ (((off_t)((fs)->fs_dsize)) * (percentreserved) / 100)) /* * Determining the size of a file block in the filesystem. */ #define blksize(fs, ip, lbn) \ (((lbn) >= NDADDR || (ip)->i_size >= smalllblktosize(fs, (lbn) + 1)) \ ? (fs)->fs_bsize \ : (fragroundup(fs, blkoff(fs, (ip)->i_size)))) #define sblksize(fs, size, lbn) \ (((lbn) >= NDADDR || (size) >= ((lbn) + 1) << (fs)->fs_bshift) \ ? (fs)->fs_bsize \ : (fragroundup(fs, blkoff(fs, (size))))) /* * Number of inodes in a secondary storage block/fragment. */ #define INOPB(fs) ((fs)->fs_inopb) #define INOPF(fs) ((fs)->fs_inopb >> (fs)->fs_fragshift) /* * Number of indirects in a filesystem block. */ #define NINDIR(fs) ((fs)->fs_nindir) extern int inside[], around[]; extern u_char *fragtbl[]; #endif partclone-0.2.86/src/ufsclone.c000066400000000000000000000156231262102574200163570ustar00rootroot00000000000000/** * ufsclone.c - part of Partclone project * * Copyright (c) 2007~ Thomas Tsai * * read ufs super block and bitmap * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ #include #include #include "ufs/ufs/dinode.h" #include "ufs/ffs/fs.h" #include "ufs/sys/disklabel.h" #include "ufs/libufs.h" #include #include #include #include #include #include #include #include #include #include #define afs disk.d_fs #define acg disk.d_cg struct uufsd disk; #include "partclone.h" #include "ufsclone.h" #include "progress.h" #include "fs_common.h" char *EXECNAME = "partclone.ufs"; extern fs_cmd_opt fs_opt; /// get_used_block - get FAT used blocks static unsigned long long get_used_block() { unsigned long long block, bused = 0, bfree = 0; int i = 0; unsigned char *p; /// read group while ((i = cgread(&disk)) != 0) { log_mesg(2, 0, 0, fs_opt.debug, "%s: \ncg = %d\n", __FILE__, disk.d_lcg); log_mesg(2, 0, 0, fs_opt.debug, "%s: blocks = %i\n", __FILE__, acg.cg_ndblk); p = cg_blksfree(&acg); for (block = 0; block < acg.cg_ndblk; block++){ if (isset(p, block)) { bfree++; } else { bused++; } } } log_mesg(1, 0, 0, fs_opt.debug, "%s: total used = %lli, total free = %lli\n", __FILE__, bused, bfree); return bused; } /// open device static void fs_open(char* device){ int fsflags = 0; log_mesg(3, 0, 0, fs_opt.debug, "%s: UFS partition Open\n", __FILE__); if (ufs_disk_fillout(&disk, device) == -1){ log_mesg(0, 1, 1, fs_opt.debug, "%s: UFS open fail\n", __FILE__); } else { log_mesg(0, 0, 0, fs_opt.debug, "%s: UFS open well\n", __FILE__); } switch (disk.d_ufs) { case 2: log_mesg(1, 0, 0, fs_opt.debug, "%s: magic = %x (UFS2)\n", __FILE__, afs.fs_magic); log_mesg(1, 0, 0, fs_opt.debug, "%s: superblock location = %lld\nid = [ %x %x ]\n", __FILE__, afs.fs_sblockloc, afs.fs_id[0], afs.fs_id[1]); log_mesg(1, 0, 0, fs_opt.debug, "%s: group (ncg) = %d\n", __FILE__, afs.fs_ncg); log_mesg(1, 0, 0, fs_opt.debug, "%s: UFS size = %lld\n", __FILE__, afs.fs_size); log_mesg(1, 0, 0, fs_opt.debug, "%s: Blocksize fs_fsize = %i\n", __FILE__, afs.fs_fsize); log_mesg(1, 0, 0, fs_opt.debug, "%s: partition size = %lld\n", __FILE__, afs.fs_size*afs.fs_fsize); log_mesg(1, 0, 0, fs_opt.debug, "%s: block per group %i\n", __FILE__, afs.fs_fpg); break; case 1: log_mesg(1, 0, 0, fs_opt.debug, "%s: magic = %x (UFS1)\n", __FILE__, afs.fs_magic); log_mesg(1, 0, 0, fs_opt.debug, "%s: superblock location = %lld\nid = [ %x %x ]\n", __FILE__, afs.fs_sblockloc, afs.fs_id[0], afs.fs_id[1]); log_mesg(1, 0, 0, fs_opt.debug, "%s: group (ncg) = %d\n", __FILE__, afs.fs_ncg); log_mesg(1, 0, 0, fs_opt.debug, "%s: UFS size = %lld\n", __FILE__, afs.fs_size); log_mesg(1, 0, 0, fs_opt.debug, "%s: Blocksize fs_fsize = %i\n", __FILE__, afs.fs_fsize); log_mesg(1, 0, 0, fs_opt.debug, "%s: partition size = %lld\n", __FILE__, afs.fs_old_size*afs.fs_fsize); log_mesg(1, 0, 0, fs_opt.debug, "%s: block per group %i\n", __FILE__, afs.fs_fpg); break; default: log_mesg(1, 0, 0, fs_opt.debug, "%s: disk.d_ufs = %c", __FILE__, disk.d_ufs); break; } /// get ufs flags if (afs.fs_old_flags & FS_FLAGS_UPDATED) fsflags = afs.fs_flags; else fsflags = afs.fs_old_flags; /// check ufs status if(fs_opt.ignore_fschk){ log_mesg(1, 0, 0, fs_opt.debug, "%s: %s: Ignore filesystem check\n", __FILE__, __FILE__); }else{ if (afs.fs_clean == 1) { log_mesg(1, 0, 0, fs_opt.debug, "%s: FS CLEAN (%i)\n", __FILE__, afs.fs_clean); } else { if ((fsflags & (FS_UNCLEAN | FS_NEEDSFSCK)) == 0) { log_mesg(0, 1, 1, fs_opt.debug, "%s: UFS flag FS_UNCLEAN or FS_NEEDSFSCK\n\n", __FILE__); } log_mesg(1, 0, 0, fs_opt.debug, "%s: FS CLEAN not set!(%i)\n", __FILE__, afs.fs_clean); } } } /// close device static void fs_close(){ log_mesg(1, 0, 0, fs_opt.debug, "%s: close\n", __FILE__); ufs_disk_close(&disk); log_mesg(1, 0, 0, fs_opt.debug, "%s: done\n\n", __FILE__); } /// readbitmap - read bitmap extern void readbitmap(char* device, image_head image_hdr, unsigned long* bitmap, int pui) { unsigned long long total_block, block, bused = 0, bfree = 0; int done = 0, i = 0, start = 0, bit_size = 1; unsigned char* p; fs_open(device); /// init progress progress_bar bprog; /// progress_bar structure defined in progress.h progress_init(&bprog, start, image_hdr.totalblock, image_hdr.totalblock, BITMAP, bit_size); total_block = 0; /// read group while ((i = cgread(&disk)) != 0) { log_mesg(2, 0, 0, fs_opt.debug, "%s: \ncg = %d\n", __FILE__, disk.d_lcg); log_mesg(2, 0, 0, fs_opt.debug, "%s: blocks = %i\n", __FILE__, acg.cg_ndblk); p = cg_blksfree(&acg); for (block = 0; block < acg.cg_ndblk; block++){ if (isset(p, block)) { pc_clear_bit(total_block, bitmap); bfree++; log_mesg(3, 0, 0, fs_opt.debug, "%s: bitmap is free %lli\n", __FILE__, block); } else { pc_set_bit(total_block, bitmap); bused++; log_mesg(3, 0, 0, fs_opt.debug, "%s: bitmap is used %lli\n", __FILE__, block); } total_block++; update_pui(&bprog, total_block, total_block,done); } log_mesg(1, 0, 0, fs_opt.debug, "%s: read bitmap done\n", __FILE__); } fs_close(); log_mesg(1, 0, 0, fs_opt.debug, "%s: total used = %lli, total free = %lli\n", __FILE__, bused, bfree); update_pui(&bprog, 1, 1, 1); } /// read super block and write to image head extern void initial_image_hdr(char* device, image_head* image_hdr) { fs_open(device); strncpy(image_hdr->magic, IMAGE_MAGIC, IMAGE_MAGIC_SIZE); strncpy(image_hdr->fs, ufs_MAGIC, FS_MAGIC_SIZE); image_hdr->block_size = afs.fs_fsize; image_hdr->usedblocks = get_used_block(); switch (disk.d_ufs) { case 2: image_hdr->totalblock = (unsigned long long)afs.fs_size; image_hdr->device_size = afs.fs_fsize*afs.fs_size; break; case 1: image_hdr->totalblock = (unsigned long long)afs.fs_old_size; image_hdr->device_size = afs.fs_fsize*afs.fs_old_size; break; default: break; } fs_close(); } partclone-0.2.86/src/ufsclone.h000066400000000000000000000012131262102574200163520ustar00rootroot00000000000000/** * reiser4clone.h - part of Partclone project * * Copyright (c) 2007~ Thomas Tsai * * read reiser4 super block and bitmap * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ /// readbitmap - read bitmap extern void readbitmap(char* device, image_head image_hdr, unsigned long* bitmap, int pui); /// read super block and write to image head extern void initial_image_hdr(char* device, image_head* image_hdr); partclone-0.2.86/src/version.h000066400000000000000000000004361262102574200162270ustar00rootroot00000000000000/* DO NOT EDIT THIS FILE - IT IS REGENERATED AT EVERY COMPILE - * IT GIVES BETTER TRACKING OF DEVELOPMENT VERSIONS * WHETHER THEY ARE BUILT BY OTHERS OR DURING DEVELOPMENT OR FOR THE * OFFICIAL PARTCLONE RELEASES. */ #define git_version "ea8fa6072c21ce06e9bec08e0f692bd8195f9de4" partclone-0.2.86/src/vmfs5clone.c000066400000000000000000000311221262102574200166120ustar00rootroot00000000000000/** * vmfsclone.c - part of Partclone project * part of source from vmfs-tools/fsck.c * * Copyright (c) 2007~ Thomas Tsai * * read vmfs super block and bitmap * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ #include #include #include #include #include #include "partclone.h" #include "reiser4clone.h" #include "progress.h" #include "fs_common.h" vmfs_fs_t *fs; vmfs_dir_t *root_dir; char *EXECNAME = "partclone.vmfs"; extern fs_cmd_opt fs_opt; unsigned long *blk_bitmap; progress_bar prog; /// progress_bar structure defined in progress.h unsigned long long checked; void *thread_update_bitmap_pui(void *arg); int bitmap_done = 0; unsigned long long total_block = 0; /* Forward declarations */ typedef struct vmfs_dir_map vmfs_dir_map_t; typedef struct vmfs_blk_map vmfs_blk_map_t; /* Directory mapping */ struct vmfs_dir_map { char *name; uint32_t blk_id; int is_dir; vmfs_blk_map_t *blk_map; }; /* * Block mapping, which allows to keep track of inodes given a block number. * Used for troubleshooting/debugging/future dump. */ #define VMFS_BLK_MAP_BUCKETS 512 #define VMFS_BLK_MAP_MAX_INODES 32 struct vmfs_blk_map { uint32_t blk_id; union { uint32_t inode_id[VMFS_BLK_MAP_MAX_INODES]; vmfs_inode_t inode; }; vmfs_dir_map_t *dir_map; u_int ref_count; u_int nlink; int status; vmfs_blk_map_t *prev,*next; }; typedef struct vmfs_dump_info vmfs_dump_info_t; struct vmfs_dump_info { vmfs_blk_map_t *blk_map[VMFS_BLK_MAP_BUCKETS]; u_int blk_count[VMFS_BLK_TYPE_MAX]; vmfs_dir_map_t *dir_map; }; /* Allocate a directory map structure */ vmfs_dir_map_t *vmfs_dir_map_alloc(const char *name,uint32_t blk_id) { vmfs_dir_map_t *map; if (!(map = calloc(1,sizeof(*map)))) return NULL; if (!(map->name = strdup(name))) { free(map); return NULL; } map->blk_id = blk_id; return map; } /* Create the root directory mapping */ vmfs_dir_map_t *vmfs_dir_map_alloc_root(void) { vmfs_dir_map_t *map; uint32_t root_blk_id; root_blk_id = VMFS_BLK_FD_BUILD(0,0,0); if (!(map = vmfs_dir_map_alloc("/",root_blk_id))) return NULL; return map; } /* Hash function for a block ID */ static inline u_int vmfs_block_map_hash(uint32_t blk_id) { return(blk_id ^ (blk_id >> 5)); } /* Find a block mapping */ vmfs_blk_map_t *vmfs_block_map_find(vmfs_blk_map_t **ht,uint32_t blk_id) { vmfs_blk_map_t *map; u_int bucket; bucket = vmfs_block_map_hash(blk_id) % VMFS_BLK_MAP_BUCKETS; for(map=ht[bucket];map;map=map->next) if (map->blk_id == blk_id) return map; return NULL; } /* Get a block mapping */ vmfs_blk_map_t *vmfs_block_map_get(vmfs_blk_map_t **ht,uint32_t blk_id) { vmfs_blk_map_t *map; u_int bucket; if ((map = vmfs_block_map_find(ht,blk_id)) != NULL) return map; if (!(map = calloc(1,sizeof(*map)))) return NULL; bucket = vmfs_block_map_hash(blk_id) % VMFS_BLK_MAP_BUCKETS; map->blk_id = blk_id; map->prev = NULL; map->next = ht[bucket]; ht[bucket] = map; return map; } /* print block id pos */ void print_pos_by_id (const vmfs_fs_t *fs, uint32_t blk_id) { unsigned long long pos = 0; uint32_t blk_type = VMFS_BLK_TYPE(blk_id); unsigned long long current = 0 ; switch(blk_type) { /* File Block */ case VMFS_BLK_TYPE_FB: pos = (unsigned long long)VMFS_BLK_FB_ITEM(blk_id) * vmfs_fs_get_blocksize(fs); /* reference vmfs-tools/libvmfs/vmfs_volume.c pos += vol->vmfs_base + 0x1000000; */ pos += 1048576 + 16777216; break; /* Sub-Block */ case VMFS_BLK_TYPE_SB: pos = vmfs_bitmap_get_item_pos(fs->sbc, VMFS_BLK_SB_ENTRY(blk_id), VMFS_BLK_SB_ITEM(blk_id)); break; /* Pointer Block */ case VMFS_BLK_TYPE_PB: pos = vmfs_bitmap_get_item_pos(fs->pbc,VMFS_BLK_PB_ENTRY(blk_id), VMFS_BLK_PB_ITEM(blk_id)); break; /* File Descriptor / Inode */ case VMFS_BLK_TYPE_FD: pos = vmfs_bitmap_get_item_pos(fs->fdc,VMFS_BLK_FD_ENTRY(blk_id), VMFS_BLK_FD_ITEM(blk_id)); break; default: log_mesg(0, 0, 0, fs_opt.debug, "Unsupported block type 0x%2.2x\n", blk_type); //fprintf(stderr,"Unsupported block type 0x%2.2x\n",blk_type); } if (checked < total_block) checked++; current = pos/vmfs_fs_get_blocksize(fs); if ( current > total_block ) log_mesg(3, 0, 0, fs_opt.debug, "total_block Error Blockid = 0x%8.8x, Type = 0x%2.2x, Pos: %llu, bitmapid: %llu, c: %llu\n", blk_id, blk_type, pos, current, checked); log_mesg(3, 0, 0, fs_opt.debug, "Blockid = 0x%8.8x, Type = 0x%2.2x, Pos: %llu, bitmapid: %llu, c: %llu\n", blk_id, blk_type, pos, current, checked); pc_set_bit(current, blk_bitmap); } /* Store block mapping of an inode */ static void vmfs_dump_store_block(const vmfs_inode_t *inode, uint32_t pb_blk, uint32_t blk_id, void *opt_arg) { vmfs_blk_map_t **ht = opt_arg; vmfs_blk_map_t *map; if (!(map = vmfs_block_map_get(ht,blk_id))) return; if (map->ref_count < VMFS_BLK_MAP_MAX_INODES) map->inode_id[map->ref_count] = inode->id; map->ref_count++; map->status = vmfs_block_get_status(inode->fs,blk_id); if (map->status <= 0){ log_mesg(0, 0, 0, fs_opt.debug, "%s: Block 0x%8.8x is used but not allocated.\n", __FILE__, blk_id); } else print_pos_by_id(inode->fs, blk_id); } /* Store inode info */ static int vmfs_dump_store_inode(const vmfs_fs_t *fs,vmfs_blk_map_t **ht, const vmfs_inode_t *inode) { vmfs_blk_map_t *map; if (!(map = vmfs_block_map_get(ht,inode->id))) return(-1); memcpy(&map->inode,inode,sizeof(*inode)); map->status = vmfs_block_get_status(fs,inode->id); if (map->status <= 0){ log_mesg(0, 0, 0, fs_opt.debug, "%s: Block 0x%8.8x is used but not allocated.\n", __FILE__, inode->id); } else print_pos_by_id(fs, inode->id); return 0; } /* dump bitmap fb */ void dump_bitmaps_fb (vmfs_bitmap_t *b,uint32_t addr, void *opt) { vmfs_fs_t *fs = opt; uint32_t blk_id; blk_id = VMFS_BLK_FB_BUILD(addr, 0); print_pos_by_id(fs, blk_id); } /* dump bitmap sb */ void dump_bitmaps_sb (vmfs_bitmap_t *b,uint32_t addr, void *opt) { vmfs_fs_t *fs = opt; uint32_t entry,item; uint32_t blk_id; entry = addr / b->bmh.items_per_bitmap_entry; item = addr % b->bmh.items_per_bitmap_entry; blk_id = VMFS_BLK_SB_BUILD(entry, item, 0); print_pos_by_id(fs, blk_id); } /* dump bitmap pb */ void dump_bitmaps_pb (vmfs_bitmap_t *b,uint32_t addr, void *opt) { vmfs_fs_t *fs = opt; uint32_t entry,item; uint32_t blk_id; entry = addr / b->bmh.items_per_bitmap_entry; item = addr % b->bmh.items_per_bitmap_entry; blk_id = VMFS_BLK_PB_BUILD(entry, item, 0); print_pos_by_id(fs, blk_id); } /* Initialize dump structures */ static void vmfs_dump_init(vmfs_dump_info_t *fi) { memset(fi,0,sizeof(*fi)); fi->dir_map = vmfs_dir_map_alloc_root(); } /// open device static void fs_open(char* device){ #ifndef VMFS5_ZLA_BASE vmfs_lvm_t *lvm; #endif vmfs_flags_t flags; char *mdev[] = {device, NULL}; vmfs_host_init(); flags.packed = 0; flags.allow_missing_extents = 1; log_mesg(3, 0, 0, fs_opt.debug, "%s: device %s\n", __FILE__, device); #ifdef VMFS5_ZLA_BASE if (!(fs=vmfs_fs_open(mdev, flags))) { log_mesg(0, 1, 1, fs_opt.debug, "%s: Unable to open volume.\n", __FILE__); } #else if (!(lvm = vmfs_lvm_create(flags))) { log_mesg(0, 1, 1, fs_opt.debug, "%s: Unable to create LVM structure\n", __FILE__); } if (vmfs_lvm_add_extent(lvm, vmfs_vol_open(device, flags)) == -1) { log_mesg(0, 1, 1, fs_opt.debug, "%s: Unable to open device/file \"%s\".\n", __FILE__, device); } if (!(fs = vmfs_fs_create(lvm))) { log_mesg(0, 1, 1, fs_opt.debug, "%s: Unable to open filesystem\n", __FILE__); } if (vmfs_fs_open(fs) == -1) { log_mesg(0, 1, 1, fs_opt.debug, "%s: Unable to open volume.\n", __FILE__); } #endif if (!(root_dir = vmfs_dir_open_from_blkid(fs,VMFS_BLK_FD_BUILD(0,0,0)))) { log_mesg(0, 1, 1, fs_opt.debug, "%s: Unable to open root directory\n", __FILE__); } } /// close device static void fs_close(){ vmfs_dir_close(root_dir); vmfs_fs_close(fs); } /// readbitmap - read bitmap extern void readbitmap(char* device, image_head image_hdr, unsigned long* bitmap, int pui) { unsigned long long used_block = 0, free_block = 0, err_block = 0; int start = 0; int bit_size = 1; vmfs_dump_info_t dump_info; vmfs_inode_t inode; vmfs_bitmap_header_t *fdc_bmp; vmfs_bitmap_t *fbb_bmp; vmfs_bitmap_t *sbc_bmp; vmfs_bitmap_t *pbc_bmp; uint32_t entry,item; uint64_t vmfs_fsinfo_base = VMFS_FSINFO_BASE; uint64_t vmfs_hb_base = VMFS_HB_BASE; uint64_t vmfs_volinfo_base = VMFS_VOLINFO_BASE; int i; int bres; pthread_t prog_bitmap_thread; fs_open(device); vmfs_dump_init(&dump_info); blk_bitmap = bitmap; /// init progress progress_init(&prog, start, image_hdr.usedblocks, image_hdr.usedblocks, BITMAP, bit_size); checked = 0; /** * thread to print progress */ bres = pthread_create(&prog_bitmap_thread, NULL, thread_update_bitmap_pui, NULL); if(bres){ log_mesg(0, 1, 1, fs_opt.debug, "%s, %i, thread create error\n", __func__, __LINE__); } /// add base pc_set_bit(vmfs_hb_base/vmfs_fs_get_blocksize(fs), bitmap); pc_set_bit(vmfs_fsinfo_base/vmfs_fs_get_blocksize(fs), bitmap); pc_set_bit(vmfs_volinfo_base/vmfs_fs_get_blocksize(fs), bitmap); fdc_bmp = &fs->fdc->bmh; log_mesg(3, 0, 0, fs_opt.debug, "Scanning %u FDC entries...\n",fdc_bmp->total_items); for(i=0;itotal_items;i++) { entry = i / fdc_bmp->items_per_bitmap_entry; item = i % fdc_bmp->items_per_bitmap_entry; /* Skip undefined/deleted inodes */ if ((vmfs_inode_get(fs,VMFS_BLK_FD_BUILD(entry,item,0),&inode) == -1) || !inode.nlink) continue; inode.fs = fs; vmfs_dump_store_inode(fs,dump_info.blk_map,&inode); vmfs_inode_foreach_block(&inode,vmfs_dump_store_block,dump_info.blk_map); } fbb_bmp = fs->fbb; sbc_bmp = fs->sbc; pbc_bmp = fs->pbc; log_mesg(3, 0, 0, fs_opt.debug, "Scanning SBC\n"); vmfs_bitmap_foreach(sbc_bmp,dump_bitmaps_sb,fs); log_mesg(3, 0, 0, fs_opt.debug, "Scanning PBC\n"); vmfs_bitmap_foreach(pbc_bmp,dump_bitmaps_pb,fs); log_mesg(3, 0, 0, fs_opt.debug, "Scanning FBB\n"); vmfs_bitmap_foreach(fbb_bmp,dump_bitmaps_fb,fs); fs_close(); bitmap_done = 1; update_pui(&prog, 1, 1, 1); log_mesg(3, 0, 0, fs_opt.debug, "checked block %llu\n", checked); log_mesg(0, 0, 0, fs_opt.debug, "%s: Used:%llu, Free:%llu, Status err:%llu\n", __FILE__, used_block, free_block, err_block); } /// read super block and write to image head extern void initial_image_hdr(char* device, image_head* image_hdr) { uint32_t alloc,total; uint32_t fdc_allocated, fbb_allocated, sbc_allocated, pbc_allocated; fs_open(device); strncpy(image_hdr->magic, IMAGE_MAGIC, IMAGE_MAGIC_SIZE); strncpy(image_hdr->fs, vmfs_MAGIC, FS_MAGIC_SIZE); total = fs->fbb->bmh.total_items; fdc_allocated = vmfs_bitmap_allocated_items(fs->fdc); fbb_allocated = vmfs_bitmap_allocated_items(fs->fbb); sbc_allocated = vmfs_bitmap_allocated_items(fs->sbc); pbc_allocated = vmfs_bitmap_allocated_items(fs->pbc); alloc = fdc_allocated + fbb_allocated + sbc_allocated + pbc_allocated; log_mesg(3, 0, 0, fs_opt.debug, "allocated fdc %"PRIu32"\n", fdc_allocated); log_mesg(3, 0, 0, fs_opt.debug, "allocated fbb %"PRIu32"\n", fbb_allocated); log_mesg(3, 0, 0, fs_opt.debug, "allocated sbc %"PRIu32"\n", sbc_allocated); log_mesg(3, 0, 0, fs_opt.debug, "allocated pbc %"PRIu32"\n", pbc_allocated); image_hdr->block_size = vmfs_fs_get_blocksize(fs); image_hdr->totalblock = total; total_block = total+100; image_hdr->usedblocks = alloc; image_hdr->device_size = (vmfs_fs_get_blocksize(fs)*total); log_mesg(3, 0, 0, fs_opt.debug, "block_size %u\n", image_hdr->block_size); log_mesg(3, 0, 0, fs_opt.debug, "totalblock %llu\n", image_hdr->totalblock); log_mesg(3, 0, 0, fs_opt.debug, "device_size %llu\n",image_hdr->device_size); log_mesg(3, 0, 0, fs_opt.debug, "usedblocks %llu\n", image_hdr->usedblocks); fs_close(); } void *thread_update_bitmap_pui(void *arg){ while (bitmap_done == 0) { update_pui(&prog, checked, checked, 0); sleep(4); } pthread_exit("exit"); } partclone-0.2.86/src/vmfsclone.c000066400000000000000000000104011262102574200165220ustar00rootroot00000000000000/** * vmfsclone.c - part of Partclone project * * Copyright (c) 2007~ Thomas Tsai * * read vmfs super block and bitmap * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ #include #include #include #include "partclone.h" #include "reiser4clone.h" #include "progress.h" #include "fs_common.h" vmfs_fs_t *fs; vmfs_dir_t *root_dir; char *EXECNAME = "partclone.vmfs"; extern fs_cmd_opt fs_opt; /// open device static void fs_open(char* device){ #ifndef VMFS5_ZLA_BASE vmfs_lvm_t *lvm; #endif vmfs_flags_t flags; char *mdev[] = {device, NULL}; vmfs_host_init(); flags.packed = 0; flags.allow_missing_extents = 1; log_mesg(3, 0, 0, fs_opt.debug, "%s: device %s\n", __FILE__, device); #ifdef VMFS5_ZLA_BASE if (!(fs=vmfs_fs_open(mdev, flags))) { #else if (!(lvm = vmfs_lvm_create(flags))) { log_mesg(0, 1, 1, fs_opt.debug, "%s: Unable to create LVM structure\n", __FILE__); } if (vmfs_lvm_add_extent(lvm, vmfs_vol_open(device, flags)) == -1) { log_mesg(0, 1, 1, fs_opt.debug, "%s: Unable to open device/file \"%s\".\n", __FILE__, device); } if (!(fs = vmfs_fs_create(lvm))) { log_mesg(0, 1, 1, fs_opt.debug, "%s: Unable to open filesystem\n", __FILE__); } if (vmfs_fs_open(fs) == -1) { #endif log_mesg(0, 1, 1, fs_opt.debug, "%s: Unable to open volume.\n", __FILE__); } if (!(root_dir = vmfs_dir_open_from_blkid(fs,VMFS_BLK_FD_BUILD(0,0,0)))) { log_mesg(0, 1, 1, fs_opt.debug, "%s: Unable to open root directory\n", __FILE__); } } /// close device static void fs_close(){ vmfs_dir_close(root_dir); vmfs_fs_close(fs); } /// calculate offset of logical volume static uint32_t logical_volume_offset(vmfs_fs_t *fs) { /* reference vmfs-tools/libvmfs/vmfs_volume.c pos += vol->vmfs_base + 0x1000000; */ return (VMFS_VOLINFO_BASE + 0x1000000) / vmfs_fs_get_blocksize(fs); } /// readbitmap - read bitmap extern void readbitmap(char* device, image_head image_hdr, unsigned long* bitmap, int pui) { uint32_t offset, total, current; uint32_t used_block = 0, free_block = 0, err_block = 0; int status = 0; int start = 0; int bit_size = 1; fs_open(device); /// init progress progress_bar prog; /// progress_bar structure defined in progress.h progress_init(&prog, start, image_hdr.totalblock, image_hdr.totalblock, BITMAP, bit_size); offset = logical_volume_offset(fs); total = fs->fbb->bmh.total_items + offset; // containing the volume information and the LVM information for(current = 0; current < offset; current++){ pc_set_bit(current, bitmap); used_block++; update_pui(&prog, current, current, 0); } // the logical volume for(current = offset; current < total; current++){ status = vmfs_block_get_status(fs, VMFS_BLK_FB_BUILD(current-offset,0)); if (status == -1) { err_block++; pc_clear_bit(current, bitmap); } else if (status == 1){ used_block++; pc_set_bit(current, bitmap); } else if (status == 0){ free_block++; pc_clear_bit(current, bitmap); } log_mesg(2, 0, 0, fs_opt.debug, "%s: Block 0x%8.8x status: %i\n", __FILE__, current, status); update_pui(&prog, current, current, 0); } fs_close(); update_pui(&prog, 1, 1, 1); log_mesg(0, 0, 0, fs_opt.debug, "%s: Used:%"PRIu32", Free:%"PRIu32", Status err:%"PRIu32"\n", __FILE__, used_block, free_block, err_block); } /// read super block and write to image head extern void initial_image_hdr(char* device, image_head* image_hdr) { uint32_t offset, total, alloc; fs_open(device); strncpy(image_hdr->magic, IMAGE_MAGIC, IMAGE_MAGIC_SIZE); strncpy(image_hdr->fs, vmfs_MAGIC, FS_MAGIC_SIZE); offset = logical_volume_offset(fs); total = fs->fbb->bmh.total_items + offset; alloc = vmfs_bitmap_allocated_items(fs->fbb) + offset; image_hdr->block_size = vmfs_fs_get_blocksize(fs); image_hdr->totalblock = total; image_hdr->usedblocks = alloc; image_hdr->device_size = (vmfs_fs_get_blocksize(fs)*total); fs_close(); } partclone-0.2.86/src/vmfsclone.h000066400000000000000000000012121262102574200165270ustar00rootroot00000000000000/** * reiser4clone.h - part of Partclone project * * Copyright (c) 2007~ Thomas Tsai * * read reiser4 super block and bitmap * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ /// readbitmap - read bitmap extern void readbitmap(char* device, image_head image_hdr, unsigned long* bitmap, int pui); /// read super block and write to image head extern void initial_image_hdr(char* device, image_head* image_hdr); partclone-0.2.86/src/xfs/000077500000000000000000000000001262102574200151665ustar00rootroot00000000000000partclone-0.2.86/src/xfs/.dirstamp000066400000000000000000000000001262102574200170000ustar00rootroot00000000000000partclone-0.2.86/src/xfs/atomic.h000066400000000000000000000023341262102574200166150ustar00rootroot00000000000000/* * Copyright (c) 2011 RedHat, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __ATOMIC_H__ #define __ATOMIC_H__ /* * Warning: These are not really atomic at all. They are wrappers around the * kernel atomic variable interface. If we do need these variables to be atomic * (due to multithreading of the code that uses them) we need to add some * pthreads magic here. */ typedef int32_t atomic_t; typedef int64_t atomic64_t; #define atomic_inc_return(x) (++(*(x))) #define atomic_dec_return(x) (--(*(x))) #define atomic64_read(x) *(x) #define atomic64_set(x, v) (*(x) = v) #endif /* __ATOMIC_H__ */ partclone-0.2.86/src/xfs/bitops.h000066400000000000000000000014401262102574200166360ustar00rootroot00000000000000#ifndef __BITOPS_H__ #define __BITOPS_H__ /* * fls: find last bit set. */ #ifndef HAVE_FLS static inline int fls(int x) { int r = 32; if (!x) return 0; if (!(x & 0xffff0000u)) { x <<= 16; r -= 16; } if (!(x & 0xff000000u)) { x <<= 8; r -= 8; } if (!(x & 0xf0000000u)) { x <<= 4; r -= 4; } if (!(x & 0xc0000000u)) { x <<= 2; r -= 2; } if (!(x & 0x80000000u)) { r -= 1; } return r; } #endif /* HAVE_FLS */ static inline int fls64(__u64 x) { __u32 h = x >> 32; if (h) return fls(h) + 32; return fls(x); } static inline unsigned fls_long(unsigned long l) { if (sizeof(l) == 4) return fls(l); return fls64(l); } /* * ffz: find first zero bit. * Result is undefined if no zero bit exists. */ #define ffz(x) ffs(~(x)) #endif partclone-0.2.86/src/xfs/cache.c000066400000000000000000000372301262102574200164020ustar00rootroot00000000000000/* * Copyright (c) 2006 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_trans_resv.h" #include "xfs_mount.h" #include "xfs_bit.h" #define CACHE_DEBUG 1 #undef CACHE_DEBUG #define CACHE_DEBUG 1 #undef CACHE_ABORT /* #define CACHE_ABORT 1 */ #define CACHE_SHAKE_COUNT 64 static unsigned int cache_generic_bulkrelse(struct cache *, struct list_head *); struct cache * cache_init( int flags, unsigned int hashsize, struct cache_operations *cache_operations) { struct cache * cache; unsigned int i, maxcount; maxcount = hashsize * HASH_CACHE_RATIO; if (!(cache = malloc(sizeof(struct cache)))) return NULL; if (!(cache->c_hash = calloc(hashsize, sizeof(struct cache_hash)))) { free(cache); return NULL; } cache->c_flags = flags; cache->c_count = 0; cache->c_max = 0; cache->c_hits = 0; cache->c_misses = 0; cache->c_maxcount = maxcount; cache->c_hashsize = hashsize; cache->c_hashshift = libxfs_highbit32(hashsize); cache->hash = cache_operations->hash; cache->alloc = cache_operations->alloc; cache->flush = cache_operations->flush; cache->relse = cache_operations->relse; cache->compare = cache_operations->compare; cache->bulkrelse = cache_operations->bulkrelse ? cache_operations->bulkrelse : cache_generic_bulkrelse; pthread_mutex_init(&cache->c_mutex, NULL); for (i = 0; i < hashsize; i++) { list_head_init(&cache->c_hash[i].ch_list); cache->c_hash[i].ch_count = 0; pthread_mutex_init(&cache->c_hash[i].ch_mutex, NULL); } for (i = 0; i <= CACHE_MAX_PRIORITY; i++) { list_head_init(&cache->c_mrus[i].cm_list); cache->c_mrus[i].cm_count = 0; pthread_mutex_init(&cache->c_mrus[i].cm_mutex, NULL); } return cache; } void cache_expand( struct cache * cache) { pthread_mutex_lock(&cache->c_mutex); #ifdef CACHE_DEBUG fprintf(stderr, "doubling cache size to %d\n", 2 * cache->c_maxcount); #endif cache->c_maxcount *= 2; pthread_mutex_unlock(&cache->c_mutex); } void cache_walk( struct cache * cache, cache_walk_t visit) { struct cache_hash * hash; struct list_head * head; struct list_head * pos; unsigned int i; for (i = 0; i < cache->c_hashsize; i++) { hash = &cache->c_hash[i]; head = &hash->ch_list; pthread_mutex_lock(&hash->ch_mutex); for (pos = head->next; pos != head; pos = pos->next) visit((struct cache_node *)pos); pthread_mutex_unlock(&hash->ch_mutex); } } #ifdef CACHE_ABORT #define cache_abort() abort() #else #define cache_abort() do { } while (0) #endif #ifdef CACHE_DEBUG static void cache_zero_check( struct cache_node * node) { if (node->cn_count > 0) { fprintf(stderr, "%s: refcount is %u, not zero (node=%p)\n", __FUNCTION__, node->cn_count, node); cache_abort(); } } #define cache_destroy_check(c) cache_walk((c), cache_zero_check) #else #define cache_destroy_check(c) do { } while (0) #endif void cache_destroy( struct cache * cache) { unsigned int i; cache_destroy_check(cache); for (i = 0; i < cache->c_hashsize; i++) { list_head_destroy(&cache->c_hash[i].ch_list); pthread_mutex_destroy(&cache->c_hash[i].ch_mutex); } for (i = 0; i <= CACHE_MAX_PRIORITY; i++) { list_head_destroy(&cache->c_mrus[i].cm_list); pthread_mutex_destroy(&cache->c_mrus[i].cm_mutex); } pthread_mutex_destroy(&cache->c_mutex); free(cache->c_hash); free(cache); } static unsigned int cache_generic_bulkrelse( struct cache * cache, struct list_head * list) { struct cache_node * node; unsigned int count = 0; while (!list_empty(list)) { node = list_entry(list->next, struct cache_node, cn_mru); pthread_mutex_destroy(&node->cn_mutex); list_del_init(&node->cn_mru); cache->relse(node); count++; } return count; } /* * We've hit the limit on cache size, so we need to start reclaiming * nodes we've used. The MRU specified by the priority is shaken. * Returns new priority at end of the call (in case we call again). */ static unsigned int cache_shake( struct cache * cache, unsigned int priority, int all) { struct cache_mru *mru; struct cache_hash * hash; struct list_head temp; struct list_head * head; struct list_head * pos; struct list_head * n; struct cache_node * node; unsigned int count; ASSERT(priority <= CACHE_MAX_PRIORITY); if (priority > CACHE_MAX_PRIORITY) priority = 0; mru = &cache->c_mrus[priority]; count = 0; list_head_init(&temp); head = &mru->cm_list; pthread_mutex_lock(&mru->cm_mutex); for (pos = head->prev, n = pos->prev; pos != head; pos = n, n = pos->prev) { node = list_entry(pos, struct cache_node, cn_mru); if (pthread_mutex_trylock(&node->cn_mutex) != 0) continue; hash = cache->c_hash + node->cn_hashidx; if (pthread_mutex_trylock(&hash->ch_mutex) != 0) { pthread_mutex_unlock(&node->cn_mutex); continue; } ASSERT(node->cn_count == 0); ASSERT(node->cn_priority == priority); node->cn_priority = -1; list_move(&node->cn_mru, &temp); list_del_init(&node->cn_hash); hash->ch_count--; mru->cm_count--; pthread_mutex_unlock(&hash->ch_mutex); pthread_mutex_unlock(&node->cn_mutex); count++; if (!all && count == CACHE_SHAKE_COUNT) break; } pthread_mutex_unlock(&mru->cm_mutex); if (count > 0) { cache->bulkrelse(cache, &temp); pthread_mutex_lock(&cache->c_mutex); cache->c_count -= count; pthread_mutex_unlock(&cache->c_mutex); } return (count == CACHE_SHAKE_COUNT) ? priority : ++priority; } /* * Allocate a new hash node (updating atomic counter in the process), * unless doing so will push us over the maximum cache size. */ static struct cache_node * cache_node_allocate( struct cache * cache, cache_key_t key) { unsigned int nodesfree; struct cache_node * node; pthread_mutex_lock(&cache->c_mutex); nodesfree = (cache->c_count < cache->c_maxcount); if (nodesfree) { cache->c_count++; if (cache->c_count > cache->c_max) cache->c_max = cache->c_count; } cache->c_misses++; pthread_mutex_unlock(&cache->c_mutex); if (!nodesfree) return NULL; node = cache->alloc(key); if (node == NULL) { /* uh-oh */ pthread_mutex_lock(&cache->c_mutex); cache->c_count--; pthread_mutex_unlock(&cache->c_mutex); return NULL; } pthread_mutex_init(&node->cn_mutex, NULL); list_head_init(&node->cn_mru); node->cn_count = 1; node->cn_priority = 0; return node; } int cache_overflowed( struct cache * cache) { return cache->c_maxcount == cache->c_max; } static int __cache_node_purge( struct cache * cache, struct cache_node * node) { int count; struct cache_mru * mru; pthread_mutex_lock(&node->cn_mutex); count = node->cn_count; if (count != 0) { pthread_mutex_unlock(&node->cn_mutex); return count; } mru = &cache->c_mrus[node->cn_priority]; pthread_mutex_lock(&mru->cm_mutex); list_del_init(&node->cn_mru); mru->cm_count--; pthread_mutex_unlock(&mru->cm_mutex); pthread_mutex_unlock(&node->cn_mutex); pthread_mutex_destroy(&node->cn_mutex); list_del_init(&node->cn_hash); cache->relse(node); return count; } /* * Lookup in the cache hash table. With any luck we'll get a cache * hit, in which case this will all be over quickly and painlessly. * Otherwise, we allocate a new node, taking care not to expand the * cache beyond the requested maximum size (shrink it if it would). * Returns one if hit in cache, otherwise zero. A node is _always_ * returned, however. */ int cache_node_get( struct cache * cache, cache_key_t key, struct cache_node ** nodep) { struct cache_node * node = NULL; struct cache_hash * hash; struct cache_mru * mru; struct list_head * head; struct list_head * pos; struct list_head * n; unsigned int hashidx; int priority = 0; int purged = 0; hashidx = cache->hash(key, cache->c_hashsize, cache->c_hashshift); hash = cache->c_hash + hashidx; head = &hash->ch_list; for (;;) { pthread_mutex_lock(&hash->ch_mutex); for (pos = head->next, n = pos->next; pos != head; pos = n, n = pos->next) { int result; node = list_entry(pos, struct cache_node, cn_hash); result = cache->compare(node, key); switch (result) { case CACHE_HIT: break; case CACHE_PURGE: if ((cache->c_flags & CACHE_MISCOMPARE_PURGE) && !__cache_node_purge(cache, node)) { purged++; hash->ch_count--; } /* FALL THROUGH */ case CACHE_MISS: goto next_object; } /* * node found, bump node's reference count, remove it * from its MRU list, and update stats. */ pthread_mutex_lock(&node->cn_mutex); if (node->cn_count == 0) { ASSERT(node->cn_priority >= 0); ASSERT(!list_empty(&node->cn_mru)); mru = &cache->c_mrus[node->cn_priority]; pthread_mutex_lock(&mru->cm_mutex); mru->cm_count--; list_del_init(&node->cn_mru); pthread_mutex_unlock(&mru->cm_mutex); } node->cn_count++; pthread_mutex_unlock(&node->cn_mutex); pthread_mutex_unlock(&hash->ch_mutex); pthread_mutex_lock(&cache->c_mutex); cache->c_hits++; pthread_mutex_unlock(&cache->c_mutex); *nodep = node; return 0; next_object: continue; /* what the hell, gcc? */ } pthread_mutex_unlock(&hash->ch_mutex); /* * not found, allocate a new entry */ node = cache_node_allocate(cache, key); if (node) break; priority = cache_shake(cache, priority, 0); /* * We start at 0; if we free CACHE_SHAKE_COUNT we get * back the same priority, if not we get back priority+1. * If we exceed CACHE_MAX_PRIORITY all slots are full; grow it. */ if (priority > CACHE_MAX_PRIORITY) { priority = 0; cache_expand(cache); } } node->cn_hashidx = hashidx; /* add new node to appropriate hash */ pthread_mutex_lock(&hash->ch_mutex); hash->ch_count++; list_add(&node->cn_hash, &hash->ch_list); pthread_mutex_unlock(&hash->ch_mutex); if (purged) { pthread_mutex_lock(&cache->c_mutex); cache->c_count -= purged; pthread_mutex_unlock(&cache->c_mutex); } *nodep = node; return 1; } void cache_node_put( struct cache * cache, struct cache_node * node) { struct cache_mru * mru; pthread_mutex_lock(&node->cn_mutex); #ifdef CACHE_DEBUG if (node->cn_count < 1) { fprintf(stderr, "%s: node put on refcount %u (node=%p)\n", __FUNCTION__, node->cn_count, node); cache_abort(); } if (!list_empty(&node->cn_mru)) { fprintf(stderr, "%s: node put on node (%p) in MRU list\n", __FUNCTION__, node); cache_abort(); } #endif node->cn_count--; if (node->cn_count == 0) { /* add unreferenced node to appropriate MRU for shaker */ mru = &cache->c_mrus[node->cn_priority]; pthread_mutex_lock(&mru->cm_mutex); mru->cm_count++; list_add(&node->cn_mru, &mru->cm_list); pthread_mutex_unlock(&mru->cm_mutex); } pthread_mutex_unlock(&node->cn_mutex); } void cache_node_set_priority( struct cache * cache, struct cache_node * node, int priority) { if (priority < 0) priority = 0; else if (priority > CACHE_MAX_PRIORITY) priority = CACHE_MAX_PRIORITY; pthread_mutex_lock(&node->cn_mutex); ASSERT(node->cn_count > 0); node->cn_priority = priority; pthread_mutex_unlock(&node->cn_mutex); } int cache_node_get_priority( struct cache_node * node) { int priority; pthread_mutex_lock(&node->cn_mutex); priority = node->cn_priority; pthread_mutex_unlock(&node->cn_mutex); return priority; } /* * Purge a specific node from the cache. Reference count must be zero. */ int cache_node_purge( struct cache * cache, cache_key_t key, struct cache_node * node) { struct list_head * head; struct list_head * pos; struct list_head * n; struct cache_hash * hash; int count = -1; hash = cache->c_hash + cache->hash(key, cache->c_hashsize, cache->c_hashshift); head = &hash->ch_list; pthread_mutex_lock(&hash->ch_mutex); for (pos = head->next, n = pos->next; pos != head; pos = n, n = pos->next) { if ((struct cache_node *)pos != node) continue; count = __cache_node_purge(cache, node); if (!count) hash->ch_count--; break; } pthread_mutex_unlock(&hash->ch_mutex); if (count == 0) { pthread_mutex_lock(&cache->c_mutex); cache->c_count--; pthread_mutex_unlock(&cache->c_mutex); } #ifdef CACHE_DEBUG if (count >= 1) { fprintf(stderr, "%s: refcount was %u, not zero (node=%p)\n", __FUNCTION__, count, node); cache_abort(); } if (count == -1) { fprintf(stderr, "%s: purge node not found! (node=%p)\n", __FUNCTION__, node); cache_abort(); } #endif return count == 0; } /* * Purge all nodes from the cache. All reference counts must be zero. */ void cache_purge( struct cache * cache) { int i; for (i = 0; i <= CACHE_MAX_PRIORITY; i++) cache_shake(cache, i, 1); #ifdef CACHE_DEBUG if (cache->c_count != 0) { /* flush referenced nodes to disk */ cache_flush(cache); fprintf(stderr, "%s: shake on cache %p left %u nodes!?\n", __FUNCTION__, cache, cache->c_count); cache_abort(); } #endif } /* * Flush all nodes in the cache to disk. */ void cache_flush( struct cache * cache) { struct cache_hash * hash; struct list_head * head; struct list_head * pos; struct cache_node * node; int i; if (!cache->flush) return; for (i = 0; i < cache->c_hashsize; i++) { hash = &cache->c_hash[i]; pthread_mutex_lock(&hash->ch_mutex); head = &hash->ch_list; for (pos = head->next; pos != head; pos = pos->next) { node = (struct cache_node *)pos; pthread_mutex_lock(&node->cn_mutex); cache->flush(node); pthread_mutex_unlock(&node->cn_mutex); } pthread_mutex_unlock(&hash->ch_mutex); } } #define HASH_REPORT (3 * HASH_CACHE_RATIO) void cache_report( FILE *fp, const char *name, struct cache *cache) { int i; unsigned long count, index, total; unsigned long hash_bucket_lengths[HASH_REPORT + 2]; if ((cache->c_hits + cache->c_misses) == 0) return; /* report cache summary */ fprintf(fp, "%s: %p\n" "Max supported entries = %u\n" "Max utilized entries = %u\n" "Active entries = %u\n" "Hash table size = %u\n" "Hits = %llu\n" "Misses = %llu\n" "Hit ratio = %5.2f\n", name, cache, cache->c_maxcount, cache->c_max, cache->c_count, cache->c_hashsize, cache->c_hits, cache->c_misses, (double)cache->c_hits * 100 / (cache->c_hits + cache->c_misses) ); for (i = 0; i <= CACHE_MAX_PRIORITY; i++) fprintf(fp, "MRU %d entries = %6u (%3u%%)\n", i, cache->c_mrus[i].cm_count, cache->c_mrus[i].cm_count * 100 / cache->c_count); /* report hash bucket lengths */ bzero(hash_bucket_lengths, sizeof(hash_bucket_lengths)); for (i = 0; i < cache->c_hashsize; i++) { count = cache->c_hash[i].ch_count; if (count > HASH_REPORT) index = HASH_REPORT + 1; else index = count; hash_bucket_lengths[index]++; } total = 0; for (i = 0; i < HASH_REPORT + 1; i++) { total += i * hash_bucket_lengths[i]; if (hash_bucket_lengths[i] == 0) continue; fprintf(fp, "Hash buckets with %2d entries %6ld (%3ld%%)\n", i, hash_bucket_lengths[i], (i * hash_bucket_lengths[i] * 100) / cache->c_count); } if (hash_bucket_lengths[i]) /* last report bucket is the overflow bucket */ fprintf(fp, "Hash buckets with >%2d entries %6ld (%3ld%%)\n", i - 1, hash_bucket_lengths[i], ((cache->c_count - total) * 100) / cache->c_count); } partclone-0.2.86/src/xfs/cache.h000066400000000000000000000107611262102574200164070ustar00rootroot00000000000000/* * Copyright (c) 2006 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __CACHE_H__ #define __CACHE_H__ /* * initialisation flags */ /* * xfs_db always writes changes immediately, and so we need to purge buffers * when we get a buffer lookup mismatch due to reading the same block with a * different buffer configuration. */ #define CACHE_MISCOMPARE_PURGE (1 << 0) /* * cache object campare return values */ enum { CACHE_HIT, CACHE_MISS, CACHE_PURGE, }; #define HASH_CACHE_RATIO 8 /* * Cache priorities range from BASE to MAX. * * For prefetch support, the top half of the range starts at * CACHE_PREFETCH_PRIORITY and everytime the buffer is fetched * and is at or above this priority level, it is reduced to * below this level (refer to libxfs_getbuf). */ #define CACHE_BASE_PRIORITY 0 #define CACHE_PREFETCH_PRIORITY 8 #define CACHE_MAX_PRIORITY 15 /* * Simple, generic implementation of a cache (arbitrary data). * Provides a hash table with a capped number of cache entries. */ struct cache; struct cache_node; typedef void *cache_key_t; typedef void (*cache_walk_t)(struct cache_node *); typedef struct cache_node * (*cache_node_alloc_t)(cache_key_t); typedef void (*cache_node_flush_t)(struct cache_node *); typedef void (*cache_node_relse_t)(struct cache_node *); typedef unsigned int (*cache_node_hash_t)(cache_key_t, unsigned int, unsigned int); typedef int (*cache_node_compare_t)(struct cache_node *, cache_key_t); typedef unsigned int (*cache_bulk_relse_t)(struct cache *, struct list_head *); struct cache_operations { cache_node_hash_t hash; cache_node_alloc_t alloc; cache_node_flush_t flush; cache_node_relse_t relse; cache_node_compare_t compare; cache_bulk_relse_t bulkrelse; /* optional */ }; struct cache_hash { struct list_head ch_list; /* hash chain head */ unsigned int ch_count; /* hash chain length */ pthread_mutex_t ch_mutex; /* hash chain mutex */ }; struct cache_mru { struct list_head cm_list; /* MRU head */ unsigned int cm_count; /* MRU length */ pthread_mutex_t cm_mutex; /* MRU lock */ }; struct cache_node { struct list_head cn_hash; /* hash chain */ struct list_head cn_mru; /* MRU chain */ unsigned int cn_count; /* reference count */ unsigned int cn_hashidx; /* hash chain index */ int cn_priority; /* priority, -1 = free list */ pthread_mutex_t cn_mutex; /* node mutex */ }; struct cache { int c_flags; /* behavioural flags */ unsigned int c_maxcount; /* max cache nodes */ unsigned int c_count; /* count of nodes */ pthread_mutex_t c_mutex; /* node count mutex */ cache_node_hash_t hash; /* node hash function */ cache_node_alloc_t alloc; /* allocation function */ cache_node_flush_t flush; /* flush dirty data function */ cache_node_relse_t relse; /* memory free function */ cache_node_compare_t compare; /* comparison routine */ cache_bulk_relse_t bulkrelse; /* bulk release routine */ unsigned int c_hashsize; /* hash bucket count */ unsigned int c_hashshift; /* hash key shift */ struct cache_hash *c_hash; /* hash table buckets */ struct cache_mru c_mrus[CACHE_MAX_PRIORITY + 1]; unsigned long long c_misses; /* cache misses */ unsigned long long c_hits; /* cache hits */ unsigned int c_max; /* max nodes ever used */ }; struct cache *cache_init(int, unsigned int, struct cache_operations *); void cache_destroy(struct cache *); void cache_walk(struct cache *, cache_walk_t); void cache_purge(struct cache *); void cache_flush(struct cache *); int cache_node_get(struct cache *, cache_key_t, struct cache_node **); void cache_node_put(struct cache *, struct cache_node *); void cache_node_set_priority(struct cache *, struct cache_node *, int); int cache_node_get_priority(struct cache_node *); int cache_node_purge(struct cache *, cache_key_t, struct cache_node *); void cache_report(FILE *fp, const char *, struct cache *); int cache_overflowed(struct cache *); #endif /* __CACHE_H__ */ partclone-0.2.86/src/xfs/command.h000066400000000000000000000033241262102574200167570ustar00rootroot00000000000000/* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __COMMAND_H__ #define __COMMAND_H__ #define CMD_FLAG_GLOBAL ((int)0x80000000) /* don't iterate "args" */ typedef int (*cfunc_t)(int argc, char **argv); typedef void (*helpfunc_t)(void); typedef struct cmdinfo { const char *name; const char *altname; cfunc_t cfunc; int argmin; int argmax; int canpush; int flags; const char *args; const char *oneline; helpfunc_t help; } cmdinfo_t; extern cmdinfo_t *cmdtab; extern int ncmds; extern void help_init(void); extern void quit_init(void); typedef int (*argsfunc_t)(int index); typedef int (*checkfunc_t)(const cmdinfo_t *ci); extern void add_command(const cmdinfo_t *ci); extern void add_user_command(char *optarg); extern void add_args_command(argsfunc_t af); extern void add_check_command(checkfunc_t cf); extern const cmdinfo_t *find_command(const char *cmd); extern void command_loop(void); extern int command_usage(const cmdinfo_t *ci); extern int command(const cmdinfo_t *ci, int argc, char **argv); #endif /* __COMMAND_H__ */ partclone-0.2.86/src/xfs/crc32.c000066400000000000000000001203521262102574200162510ustar00rootroot00000000000000/* * Aug 8, 2011 Bob Pearson with help from Joakim Tjernlund and George Spelvin * cleaned up code to current version of sparse and added the slicing-by-8 * algorithm to the closely similar existing slicing-by-4 algorithm. * * Oct 15, 2000 Matt Domsch * Nicer crc32 functions/docs submitted by linux@horizon.com. Thanks! * Code was from the public domain, copyright abandoned. Code was * subsequently included in the kernel, thus was re-licensed under the * GNU GPL v2. * * Oct 12, 2000 Matt Domsch * Same crc32 function was used in 5 other places in the kernel. * I made one version, and deleted the others. * There are various incantations of crc32(). Some use a seed of 0 or ~0. * Some xor at the end with ~0. The generic crc32() function takes * seed as an argument, and doesn't xor at the end. Then individual * users can do whatever they need. * drivers/net/smc9194.c uses seed ~0, doesn't xor with ~0. * fs/jffs2 uses seed 0, doesn't xor with ~0. * fs/partitions/efi.c uses seed ~0, xor's with ~0. * * This source code is licensed under the GNU General Public License, * Version 2. See the file COPYING for more details. */ /* see: Documentation/crc32.txt for a description of algorithms */ /* * lifted from the 3.8-rc2 kernel source for xfsprogs. Killed CONFIG_X86 * specific bits for just the generic algorithm. Also removed the big endian * version of the algorithm as XFS only uses the little endian CRC version to * match the hardware acceleration available on Intel CPUs. */ #include "platform_defs.h" #include "xfs.h" #include "xfs_arch.h" #include "crc32defs.h" /* types specifc to this file */ typedef __u8 u8; typedef __u16 u16; typedef __u32 u32; typedef __u32 u64; #define __pure #if CRC_LE_BITS > 8 # define tole(x) ((__force u32) __constant_cpu_to_le32(x)) #else # define tole(x) (x) #endif #if CRC_BE_BITS > 8 # define tobe(x) ((__force u32) __constant_cpu_to_be32(x)) #else # define tobe(x) (x) #endif #include "crc32table.h" #if CRC_LE_BITS > 8 || CRC_BE_BITS > 8 /* implements slicing-by-4 or slicing-by-8 algorithm */ static inline u32 crc32_body(u32 crc, unsigned char const *buf, size_t len, const u32 (*tab)[256]) { #if __BYTE_ORDER == __LITTLE_ENDIAN # define DO_CRC(x) crc = t0[(crc ^ (x)) & 255] ^ (crc >> 8) # define DO_CRC4 (t3[(q) & 255] ^ t2[(q >> 8) & 255] ^ \ t1[(q >> 16) & 255] ^ t0[(q >> 24) & 255]) # define DO_CRC8 (t7[(q) & 255] ^ t6[(q >> 8) & 255] ^ \ t5[(q >> 16) & 255] ^ t4[(q >> 24) & 255]) # elif __BYTE_ORDER == __BIG_ENDIAN # define DO_CRC(x) crc = t0[((crc >> 24) ^ (x)) & 255] ^ (crc << 8) # define DO_CRC4 (t0[(q) & 255] ^ t1[(q >> 8) & 255] ^ \ t2[(q >> 16) & 255] ^ t3[(q >> 24) & 255]) # define DO_CRC8 (t4[(q) & 255] ^ t5[(q >> 8) & 255] ^ \ t6[(q >> 16) & 255] ^ t7[(q >> 24) & 255]) # else # error What endian are you? # endif const u32 *b; size_t rem_len; const u32 *t0=tab[0], *t1=tab[1], *t2=tab[2], *t3=tab[3]; # if CRC_LE_BITS != 32 const u32 *t4 = tab[4], *t5 = tab[5], *t6 = tab[6], *t7 = tab[7]; # endif u32 q; /* Align it */ if (((long)buf & 3) && len) { do { DO_CRC(*buf++); } while ((--len) && ((long)buf)&3); } # if CRC_LE_BITS == 32 rem_len = len & 3; len = len >> 2; # else rem_len = len & 7; len = len >> 3; # endif b = (const u32 *)buf; for (--b; len; --len) { q = crc ^ *++b; /* use pre increment for speed */ # if CRC_LE_BITS == 32 crc = DO_CRC4; # else crc = DO_CRC8; q = *++b; crc ^= DO_CRC4; # endif } len = rem_len; /* And the last few bytes */ if (len) { u8 *p = (u8 *)(b + 1) - 1; do { DO_CRC(*++p); /* use pre increment for speed */ } while (--len); } return crc; #undef DO_CRC #undef DO_CRC4 #undef DO_CRC8 } #endif /** * crc32_le() - Calculate bitwise little-endian Ethernet AUTODIN II CRC32 * @crc: seed value for computation. ~0 for Ethernet, sometimes 0 for * other uses, or the previous crc32 value if computing incrementally. * @p: pointer to buffer over which CRC is run * @len: length of buffer @p */ static inline u32 __pure crc32_le_generic(u32 crc, unsigned char const *p, size_t len, const u32 (*tab)[256], u32 polynomial) { #if CRC_LE_BITS == 1 int i; while (len--) { crc ^= *p++; for (i = 0; i < 8; i++) crc = (crc >> 1) ^ ((crc & 1) ? polynomial : 0); } # elif CRC_LE_BITS == 2 while (len--) { crc ^= *p++; crc = (crc >> 2) ^ tab[0][crc & 3]; crc = (crc >> 2) ^ tab[0][crc & 3]; crc = (crc >> 2) ^ tab[0][crc & 3]; crc = (crc >> 2) ^ tab[0][crc & 3]; } # elif CRC_LE_BITS == 4 while (len--) { crc ^= *p++; crc = (crc >> 4) ^ tab[0][crc & 15]; crc = (crc >> 4) ^ tab[0][crc & 15]; } # elif CRC_LE_BITS == 8 /* aka Sarwate algorithm */ while (len--) { crc ^= *p++; crc = (crc >> 8) ^ tab[0][crc & 255]; } # else crc = (__force u32) cpu_to_le32(crc); crc = crc32_body(crc, p, len, tab); crc = le32_to_cpu((__force __le32)crc); #endif return crc; } #if CRC_LE_BITS == 1 u32 __pure crc32_le(u32 crc, unsigned char const *p, size_t len) { return crc32_le_generic(crc, p, len, NULL, CRCPOLY_LE); } u32 __pure crc32c_le(u32 crc, unsigned char const *p, size_t len) { return crc32_le_generic(crc, p, len, NULL, CRC32C_POLY_LE); } #else u32 __pure crc32_le(u32 crc, unsigned char const *p, size_t len) { return crc32_le_generic(crc, p, len, (const u32 (*)[256])crc32table_le, CRCPOLY_LE); } u32 __pure crc32c_le(u32 crc, unsigned char const *p, size_t len) { return crc32_le_generic(crc, p, len, (const u32 (*)[256])crc32ctable_le, CRC32C_POLY_LE); } #endif #ifdef CRC32_SELFTEST /* 4096 random bytes */ static u8 __attribute__((__aligned__(8))) test_buf[] = { 0x5b, 0x85, 0x21, 0xcb, 0x09, 0x68, 0x7d, 0x30, 0xc7, 0x69, 0xd7, 0x30, 0x92, 0xde, 0x59, 0xe4, 0xc9, 0x6e, 0x8b, 0xdb, 0x98, 0x6b, 0xaa, 0x60, 0xa8, 0xb5, 0xbc, 0x6c, 0xa9, 0xb1, 0x5b, 0x2c, 0xea, 0xb4, 0x92, 0x6a, 0x3f, 0x79, 0x91, 0xe4, 0xe9, 0x70, 0x51, 0x8c, 0x7f, 0x95, 0x6f, 0x1a, 0x56, 0xa1, 0x5c, 0x27, 0x03, 0x67, 0x9f, 0x3a, 0xe2, 0x31, 0x11, 0x29, 0x6b, 0x98, 0xfc, 0xc4, 0x53, 0x24, 0xc5, 0x8b, 0xce, 0x47, 0xb2, 0xb9, 0x32, 0xcb, 0xc1, 0xd0, 0x03, 0x57, 0x4e, 0xd4, 0xe9, 0x3c, 0xa1, 0x63, 0xcf, 0x12, 0x0e, 0xca, 0xe1, 0x13, 0xd1, 0x93, 0xa6, 0x88, 0x5c, 0x61, 0x5b, 0xbb, 0xf0, 0x19, 0x46, 0xb4, 0xcf, 0x9e, 0xb6, 0x6b, 0x4c, 0x3a, 0xcf, 0x60, 0xf9, 0x7a, 0x8d, 0x07, 0x63, 0xdb, 0x40, 0xe9, 0x0b, 0x6f, 0xad, 0x97, 0xf1, 0xed, 0xd0, 0x1e, 0x26, 0xfd, 0xbf, 0xb7, 0xc8, 0x04, 0x94, 0xf8, 0x8b, 0x8c, 0xf1, 0xab, 0x7a, 0xd4, 0xdd, 0xf3, 0xe8, 0x88, 0xc3, 0xed, 0x17, 0x8a, 0x9b, 0x40, 0x0d, 0x53, 0x62, 0x12, 0x03, 0x5f, 0x1b, 0x35, 0x32, 0x1f, 0xb4, 0x7b, 0x93, 0x78, 0x0d, 0xdb, 0xce, 0xa4, 0xc0, 0x47, 0xd5, 0xbf, 0x68, 0xe8, 0x5d, 0x74, 0x8f, 0x8e, 0x75, 0x1c, 0xb2, 0x4f, 0x9a, 0x60, 0xd1, 0xbe, 0x10, 0xf4, 0x5c, 0xa1, 0x53, 0x09, 0xa5, 0xe0, 0x09, 0x54, 0x85, 0x5c, 0xdc, 0x07, 0xe7, 0x21, 0x69, 0x7b, 0x8a, 0xfd, 0x90, 0xf1, 0x22, 0xd0, 0xb4, 0x36, 0x28, 0xe6, 0xb8, 0x0f, 0x39, 0xde, 0xc8, 0xf3, 0x86, 0x60, 0x34, 0xd2, 0x5e, 0xdf, 0xfd, 0xcf, 0x0f, 0xa9, 0x65, 0xf0, 0xd5, 0x4d, 0x96, 0x40, 0xe3, 0xdf, 0x3f, 0x95, 0x5a, 0x39, 0x19, 0x93, 0xf4, 0x75, 0xce, 0x22, 0x00, 0x1c, 0x93, 0xe2, 0x03, 0x66, 0xf4, 0x93, 0x73, 0x86, 0x81, 0x8e, 0x29, 0x44, 0x48, 0x86, 0x61, 0x7c, 0x48, 0xa3, 0x43, 0xd2, 0x9c, 0x8d, 0xd4, 0x95, 0xdd, 0xe1, 0x22, 0x89, 0x3a, 0x40, 0x4c, 0x1b, 0x8a, 0x04, 0xa8, 0x09, 0x69, 0x8b, 0xea, 0xc6, 0x55, 0x8e, 0x57, 0xe6, 0x64, 0x35, 0xf0, 0xc7, 0x16, 0x9f, 0x5d, 0x5e, 0x86, 0x40, 0x46, 0xbb, 0xe5, 0x45, 0x88, 0xfe, 0xc9, 0x63, 0x15, 0xfb, 0xf5, 0xbd, 0x71, 0x61, 0xeb, 0x7b, 0x78, 0x70, 0x07, 0x31, 0x03, 0x9f, 0xb2, 0xc8, 0xa7, 0xab, 0x47, 0xfd, 0xdf, 0xa0, 0x78, 0x72, 0xa4, 0x2a, 0xe4, 0xb6, 0xba, 0xc0, 0x1e, 0x86, 0x71, 0xe6, 0x3d, 0x18, 0x37, 0x70, 0xe6, 0xff, 0xe0, 0xbc, 0x0b, 0x22, 0xa0, 0x1f, 0xd3, 0xed, 0xa2, 0x55, 0x39, 0xab, 0xa8, 0x13, 0x73, 0x7c, 0x3f, 0xb2, 0xd6, 0x19, 0xac, 0xff, 0x99, 0xed, 0xe8, 0xe6, 0xa6, 0x22, 0xe3, 0x9c, 0xf1, 0x30, 0xdc, 0x01, 0x0a, 0x56, 0xfa, 0xe4, 0xc9, 0x99, 0xdd, 0xa8, 0xd8, 0xda, 0x35, 0x51, 0x73, 0xb4, 0x40, 0x86, 0x85, 0xdb, 0x5c, 0xd5, 0x85, 0x80, 0x14, 0x9c, 0xfd, 0x98, 0xa9, 0x82, 0xc5, 0x37, 0xff, 0x32, 0x5d, 0xd0, 0x0b, 0xfa, 0xdc, 0x04, 0x5e, 0x09, 0xd2, 0xca, 0x17, 0x4b, 0x1a, 0x8e, 0x15, 0xe1, 0xcc, 0x4e, 0x52, 0x88, 0x35, 0xbd, 0x48, 0xfe, 0x15, 0xa0, 0x91, 0xfd, 0x7e, 0x6c, 0x0e, 0x5d, 0x79, 0x1b, 0x81, 0x79, 0xd2, 0x09, 0x34, 0x70, 0x3d, 0x81, 0xec, 0xf6, 0x24, 0xbb, 0xfb, 0xf1, 0x7b, 0xdf, 0x54, 0xea, 0x80, 0x9b, 0xc7, 0x99, 0x9e, 0xbd, 0x16, 0x78, 0x12, 0x53, 0x5e, 0x01, 0xa7, 0x4e, 0xbd, 0x67, 0xe1, 0x9b, 0x4c, 0x0e, 0x61, 0x45, 0x97, 0xd2, 0xf0, 0x0f, 0xfe, 0x15, 0x08, 0xb7, 0x11, 0x4c, 0xe7, 0xff, 0x81, 0x53, 0xff, 0x91, 0x25, 0x38, 0x7e, 0x40, 0x94, 0xe5, 0xe0, 0xad, 0xe6, 0xd9, 0x79, 0xb6, 0x92, 0xc9, 0xfc, 0xde, 0xc3, 0x1a, 0x23, 0xbb, 0xdd, 0xc8, 0x51, 0x0c, 0x3a, 0x72, 0xfa, 0x73, 0x6f, 0xb7, 0xee, 0x61, 0x39, 0x03, 0x01, 0x3f, 0x7f, 0x94, 0x2e, 0x2e, 0xba, 0x3a, 0xbb, 0xb4, 0xfa, 0x6a, 0x17, 0xfe, 0xea, 0xef, 0x5e, 0x66, 0x97, 0x3f, 0x32, 0x3d, 0xd7, 0x3e, 0xb1, 0xf1, 0x6c, 0x14, 0x4c, 0xfd, 0x37, 0xd3, 0x38, 0x80, 0xfb, 0xde, 0xa6, 0x24, 0x1e, 0xc8, 0xca, 0x7f, 0x3a, 0x93, 0xd8, 0x8b, 0x18, 0x13, 0xb2, 0xe5, 0xe4, 0x93, 0x05, 0x53, 0x4f, 0x84, 0x66, 0xa7, 0x58, 0x5c, 0x7b, 0x86, 0x52, 0x6d, 0x0d, 0xce, 0xa4, 0x30, 0x7d, 0xb6, 0x18, 0x9f, 0xeb, 0xff, 0x22, 0xbb, 0x72, 0x29, 0xb9, 0x44, 0x0b, 0x48, 0x1e, 0x84, 0x71, 0x81, 0xe3, 0x6d, 0x73, 0x26, 0x92, 0xb4, 0x4d, 0x2a, 0x29, 0xb8, 0x1f, 0x72, 0xed, 0xd0, 0xe1, 0x64, 0x77, 0xea, 0x8e, 0x88, 0x0f, 0xef, 0x3f, 0xb1, 0x3b, 0xad, 0xf9, 0xc9, 0x8b, 0xd0, 0xac, 0xc6, 0xcc, 0xa9, 0x40, 0xcc, 0x76, 0xf6, 0x3b, 0x53, 0xb5, 0x88, 0xcb, 0xc8, 0x37, 0xf1, 0xa2, 0xba, 0x23, 0x15, 0x99, 0x09, 0xcc, 0xe7, 0x7a, 0x3b, 0x37, 0xf7, 0x58, 0xc8, 0x46, 0x8c, 0x2b, 0x2f, 0x4e, 0x0e, 0xa6, 0x5c, 0xea, 0x85, 0x55, 0xba, 0x02, 0x0e, 0x0e, 0x48, 0xbc, 0xe1, 0xb1, 0x01, 0x35, 0x79, 0x13, 0x3d, 0x1b, 0xc0, 0x53, 0x68, 0x11, 0xe7, 0x95, 0x0f, 0x9d, 0x3f, 0x4c, 0x47, 0x7b, 0x4d, 0x1c, 0xae, 0x50, 0x9b, 0xcb, 0xdd, 0x05, 0x8d, 0x9a, 0x97, 0xfd, 0x8c, 0xef, 0x0c, 0x1d, 0x67, 0x73, 0xa8, 0x28, 0x36, 0xd5, 0xb6, 0x92, 0x33, 0x40, 0x75, 0x0b, 0x51, 0xc3, 0x64, 0xba, 0x1d, 0xc2, 0xcc, 0xee, 0x7d, 0x54, 0x0f, 0x27, 0x69, 0xa7, 0x27, 0x63, 0x30, 0x29, 0xd9, 0xc8, 0x84, 0xd8, 0xdf, 0x9f, 0x68, 0x8d, 0x04, 0xca, 0xa6, 0xc5, 0xc7, 0x7a, 0x5c, 0xc8, 0xd1, 0xcb, 0x4a, 0xec, 0xd0, 0xd8, 0x20, 0x69, 0xc5, 0x17, 0xcd, 0x78, 0xc8, 0x75, 0x23, 0x30, 0x69, 0xc9, 0xd4, 0xea, 0x5c, 0x4f, 0x6b, 0x86, 0x3f, 0x8b, 0xfe, 0xee, 0x44, 0xc9, 0x7c, 0xb7, 0xdd, 0x3e, 0xe5, 0xec, 0x54, 0x03, 0x3e, 0xaa, 0x82, 0xc6, 0xdf, 0xb2, 0x38, 0x0e, 0x5d, 0xb3, 0x88, 0xd9, 0xd3, 0x69, 0x5f, 0x8f, 0x70, 0x8a, 0x7e, 0x11, 0xd9, 0x1e, 0x7b, 0x38, 0xf1, 0x42, 0x1a, 0xc0, 0x35, 0xf5, 0xc7, 0x36, 0x85, 0xf5, 0xf7, 0xb8, 0x7e, 0xc7, 0xef, 0x18, 0xf1, 0x63, 0xd6, 0x7a, 0xc6, 0xc9, 0x0e, 0x4d, 0x69, 0x4f, 0x84, 0xef, 0x26, 0x41, 0x0c, 0xec, 0xc7, 0xe0, 0x7e, 0x3c, 0x67, 0x01, 0x4c, 0x62, 0x1a, 0x20, 0x6f, 0xee, 0x47, 0x4d, 0xc0, 0x99, 0x13, 0x8d, 0x91, 0x4a, 0x26, 0xd4, 0x37, 0x28, 0x90, 0x58, 0x75, 0x66, 0x2b, 0x0a, 0xdf, 0xda, 0xee, 0x92, 0x25, 0x90, 0x62, 0x39, 0x9e, 0x44, 0x98, 0xad, 0xc1, 0x88, 0xed, 0xe4, 0xb4, 0xaf, 0xf5, 0x8c, 0x9b, 0x48, 0x4d, 0x56, 0x60, 0x97, 0x0f, 0x61, 0x59, 0x9e, 0xa6, 0x27, 0xfe, 0xc1, 0x91, 0x15, 0x38, 0xb8, 0x0f, 0xae, 0x61, 0x7d, 0x26, 0x13, 0x5a, 0x73, 0xff, 0x1c, 0xa3, 0x61, 0x04, 0x58, 0x48, 0x55, 0x44, 0x11, 0xfe, 0x15, 0xca, 0xc3, 0xbd, 0xca, 0xc5, 0xb4, 0x40, 0x5d, 0x1b, 0x7f, 0x39, 0xb5, 0x9c, 0x35, 0xec, 0x61, 0x15, 0x32, 0x32, 0xb8, 0x4e, 0x40, 0x9f, 0x17, 0x1f, 0x0a, 0x4d, 0xa9, 0x91, 0xef, 0xb7, 0xb0, 0xeb, 0xc2, 0x83, 0x9a, 0x6c, 0xd2, 0x79, 0x43, 0x78, 0x5e, 0x2f, 0xe5, 0xdd, 0x1a, 0x3c, 0x45, 0xab, 0x29, 0x40, 0x3a, 0x37, 0x5b, 0x6f, 0xd7, 0xfc, 0x48, 0x64, 0x3c, 0x49, 0xfb, 0x21, 0xbe, 0xc3, 0xff, 0x07, 0xfb, 0x17, 0xe9, 0xc9, 0x0c, 0x4c, 0x5c, 0x15, 0x9e, 0x8e, 0x22, 0x30, 0x0a, 0xde, 0x48, 0x7f, 0xdb, 0x0d, 0xd1, 0x2b, 0x87, 0x38, 0x9e, 0xcc, 0x5a, 0x01, 0x16, 0xee, 0x75, 0x49, 0x0d, 0x30, 0x01, 0x34, 0x6a, 0xb6, 0x9a, 0x5a, 0x2a, 0xec, 0xbb, 0x48, 0xac, 0xd3, 0x77, 0x83, 0xd8, 0x08, 0x86, 0x4f, 0x48, 0x09, 0x29, 0x41, 0x79, 0xa1, 0x03, 0x12, 0xc4, 0xcd, 0x90, 0x55, 0x47, 0x66, 0x74, 0x9a, 0xcc, 0x4f, 0x35, 0x8c, 0xd6, 0x98, 0xef, 0xeb, 0x45, 0xb9, 0x9a, 0x26, 0x2f, 0x39, 0xa5, 0x70, 0x6d, 0xfc, 0xb4, 0x51, 0xee, 0xf4, 0x9c, 0xe7, 0x38, 0x59, 0xad, 0xf4, 0xbc, 0x46, 0xff, 0x46, 0x8e, 0x60, 0x9c, 0xa3, 0x60, 0x1d, 0xf8, 0x26, 0x72, 0xf5, 0x72, 0x9d, 0x68, 0x80, 0x04, 0xf6, 0x0b, 0xa1, 0x0a, 0xd5, 0xa7, 0x82, 0x3a, 0x3e, 0x47, 0xa8, 0x5a, 0xde, 0x59, 0x4f, 0x7b, 0x07, 0xb3, 0xe9, 0x24, 0x19, 0x3d, 0x34, 0x05, 0xec, 0xf1, 0xab, 0x6e, 0x64, 0x8f, 0xd3, 0xe6, 0x41, 0x86, 0x80, 0x70, 0xe3, 0x8d, 0x60, 0x9c, 0x34, 0x25, 0x01, 0x07, 0x4d, 0x19, 0x41, 0x4e, 0x3d, 0x5c, 0x7e, 0xa8, 0xf5, 0xcc, 0xd5, 0x7b, 0xe2, 0x7d, 0x3d, 0x49, 0x86, 0x7d, 0x07, 0xb7, 0x10, 0xe3, 0x35, 0xb8, 0x84, 0x6d, 0x76, 0xab, 0x17, 0xc6, 0x38, 0xb4, 0xd3, 0x28, 0x57, 0xad, 0xd3, 0x88, 0x5a, 0xda, 0xea, 0xc8, 0x94, 0xcc, 0x37, 0x19, 0xac, 0x9c, 0x9f, 0x4b, 0x00, 0x15, 0xc0, 0xc8, 0xca, 0x1f, 0x15, 0xaa, 0xe0, 0xdb, 0xf9, 0x2f, 0x57, 0x1b, 0x24, 0xc7, 0x6f, 0x76, 0x29, 0xfb, 0xed, 0x25, 0x0d, 0xc0, 0xfe, 0xbd, 0x5a, 0xbf, 0x20, 0x08, 0x51, 0x05, 0xec, 0x71, 0xa3, 0xbf, 0xef, 0x5e, 0x99, 0x75, 0xdb, 0x3c, 0x5f, 0x9a, 0x8c, 0xbb, 0x19, 0x5c, 0x0e, 0x93, 0x19, 0xf8, 0x6a, 0xbc, 0xf2, 0x12, 0x54, 0x2f, 0xcb, 0x28, 0x64, 0x88, 0xb3, 0x92, 0x0d, 0x96, 0xd1, 0xa6, 0xe4, 0x1f, 0xf1, 0x4d, 0xa4, 0xab, 0x1c, 0xee, 0x54, 0xf2, 0xad, 0x29, 0x6d, 0x32, 0x37, 0xb2, 0x16, 0x77, 0x5c, 0xdc, 0x2e, 0x54, 0xec, 0x75, 0x26, 0xc6, 0x36, 0xd9, 0x17, 0x2c, 0xf1, 0x7a, 0xdc, 0x4b, 0xf1, 0xe2, 0xd9, 0x95, 0xba, 0xac, 0x87, 0xc1, 0xf3, 0x8e, 0x58, 0x08, 0xd8, 0x87, 0x60, 0xc9, 0xee, 0x6a, 0xde, 0xa4, 0xd2, 0xfc, 0x0d, 0xe5, 0x36, 0xc4, 0x5c, 0x52, 0xb3, 0x07, 0x54, 0x65, 0x24, 0xc1, 0xb1, 0xd1, 0xb1, 0x53, 0x13, 0x31, 0x79, 0x7f, 0x05, 0x76, 0xeb, 0x37, 0x59, 0x15, 0x2b, 0xd1, 0x3f, 0xac, 0x08, 0x97, 0xeb, 0x91, 0x98, 0xdf, 0x6c, 0x09, 0x0d, 0x04, 0x9f, 0xdc, 0x3b, 0x0e, 0x60, 0x68, 0x47, 0x23, 0x15, 0x16, 0xc6, 0x0b, 0x35, 0xf8, 0x77, 0xa2, 0x78, 0x50, 0xd4, 0x64, 0x22, 0x33, 0xff, 0xfb, 0x93, 0x71, 0x46, 0x50, 0x39, 0x1b, 0x9c, 0xea, 0x4e, 0x8d, 0x0c, 0x37, 0xe5, 0x5c, 0x51, 0x3a, 0x31, 0xb2, 0x85, 0x84, 0x3f, 0x41, 0xee, 0xa2, 0xc1, 0xc6, 0x13, 0x3b, 0x54, 0x28, 0xd2, 0x18, 0x37, 0xcc, 0x46, 0x9f, 0x6a, 0x91, 0x3d, 0x5a, 0x15, 0x3c, 0x89, 0xa3, 0x61, 0x06, 0x7d, 0x2e, 0x78, 0xbe, 0x7d, 0x40, 0xba, 0x2f, 0x95, 0xb1, 0x2f, 0x87, 0x3b, 0x8a, 0xbe, 0x6a, 0xf4, 0xc2, 0x31, 0x74, 0xee, 0x91, 0xe0, 0x23, 0xaa, 0x5d, 0x7f, 0xdd, 0xf0, 0x44, 0x8c, 0x0b, 0x59, 0x2b, 0xfc, 0x48, 0x3a, 0xdf, 0x07, 0x05, 0x38, 0x6c, 0xc9, 0xeb, 0x18, 0x24, 0x68, 0x8d, 0x58, 0x98, 0xd3, 0x31, 0xa3, 0xe4, 0x70, 0x59, 0xb1, 0x21, 0xbe, 0x7e, 0x65, 0x7d, 0xb8, 0x04, 0xab, 0xf6, 0xe4, 0xd7, 0xda, 0xec, 0x09, 0x8f, 0xda, 0x6d, 0x24, 0x07, 0xcc, 0x29, 0x17, 0x05, 0x78, 0x1a, 0xc1, 0xb1, 0xce, 0xfc, 0xaa, 0x2d, 0xe7, 0xcc, 0x85, 0x84, 0x84, 0x03, 0x2a, 0x0c, 0x3f, 0xa9, 0xf8, 0xfd, 0x84, 0x53, 0x59, 0x5c, 0xf0, 0xd4, 0x09, 0xf0, 0xd2, 0x6c, 0x32, 0x03, 0xb0, 0xa0, 0x8c, 0x52, 0xeb, 0x23, 0x91, 0x88, 0x43, 0x13, 0x46, 0xf6, 0x1e, 0xb4, 0x1b, 0xf5, 0x8e, 0x3a, 0xb5, 0x3d, 0x00, 0xf6, 0xe5, 0x08, 0x3d, 0x5f, 0x39, 0xd3, 0x21, 0x69, 0xbc, 0x03, 0x22, 0x3a, 0xd2, 0x5c, 0x84, 0xf8, 0x15, 0xc4, 0x80, 0x0b, 0xbc, 0x29, 0x3c, 0xf3, 0x95, 0x98, 0xcd, 0x8f, 0x35, 0xbc, 0xa5, 0x3e, 0xfc, 0xd4, 0x13, 0x9e, 0xde, 0x4f, 0xce, 0x71, 0x9d, 0x09, 0xad, 0xf2, 0x80, 0x6b, 0x65, 0x7f, 0x03, 0x00, 0x14, 0x7c, 0x15, 0x85, 0x40, 0x6d, 0x70, 0xea, 0xdc, 0xb3, 0x63, 0x35, 0x4f, 0x4d, 0xe0, 0xd9, 0xd5, 0x3c, 0x58, 0x56, 0x23, 0x80, 0xe2, 0x36, 0xdd, 0x75, 0x1d, 0x94, 0x11, 0x41, 0x8e, 0xe0, 0x81, 0x8e, 0xcf, 0xe0, 0xe5, 0xf6, 0xde, 0xd1, 0xe7, 0x04, 0x12, 0x79, 0x92, 0x2b, 0x71, 0x2a, 0x79, 0x8b, 0x7c, 0x44, 0x79, 0x16, 0x30, 0x4e, 0xf4, 0xf6, 0x9b, 0xb7, 0x40, 0xa3, 0x5a, 0xa7, 0x69, 0x3e, 0xc1, 0x3a, 0x04, 0xd0, 0x88, 0xa0, 0x3b, 0xdd, 0xc6, 0x9e, 0x7e, 0x1e, 0x1e, 0x8f, 0x44, 0xf7, 0x73, 0x67, 0x1e, 0x1a, 0x78, 0xfa, 0x62, 0xf4, 0xa9, 0xa8, 0xc6, 0x5b, 0xb8, 0xfa, 0x06, 0x7d, 0x5e, 0x38, 0x1c, 0x9a, 0x39, 0xe9, 0x39, 0x98, 0x22, 0x0b, 0xa7, 0xac, 0x0b, 0xf3, 0xbc, 0xf1, 0xeb, 0x8c, 0x81, 0xe3, 0x48, 0x8a, 0xed, 0x42, 0xc2, 0x38, 0xcf, 0x3e, 0xda, 0xd2, 0x89, 0x8d, 0x9c, 0x53, 0xb5, 0x2f, 0x41, 0x01, 0x26, 0x84, 0x9c, 0xa3, 0x56, 0xf6, 0x49, 0xc7, 0xd4, 0x9f, 0x93, 0x1b, 0x96, 0x49, 0x5e, 0xad, 0xb3, 0x84, 0x1f, 0x3c, 0xa4, 0xe0, 0x9b, 0xd1, 0x90, 0xbc, 0x38, 0x6c, 0xdd, 0x95, 0x4d, 0x9d, 0xb1, 0x71, 0x57, 0x2d, 0x34, 0xe8, 0xb8, 0x42, 0xc7, 0x99, 0x03, 0xc7, 0x07, 0x30, 0x65, 0x91, 0x55, 0xd5, 0x90, 0x70, 0x97, 0x37, 0x68, 0xd4, 0x11, 0xf9, 0xe8, 0xce, 0xec, 0xdc, 0x34, 0xd5, 0xd3, 0xb7, 0xc4, 0xb8, 0x97, 0x05, 0x92, 0xad, 0xf8, 0xe2, 0x36, 0x64, 0x41, 0xc9, 0xc5, 0x41, 0x77, 0x52, 0xd7, 0x2c, 0xa5, 0x24, 0x2f, 0xd9, 0x34, 0x0b, 0x47, 0x35, 0xa7, 0x28, 0x8b, 0xc5, 0xcd, 0xe9, 0x46, 0xac, 0x39, 0x94, 0x3c, 0x10, 0xc6, 0x29, 0x73, 0x0e, 0x0e, 0x5d, 0xe0, 0x71, 0x03, 0x8a, 0x72, 0x0e, 0x26, 0xb0, 0x7d, 0x84, 0xed, 0x95, 0x23, 0x49, 0x5a, 0x45, 0x83, 0x45, 0x60, 0x11, 0x4a, 0x46, 0x31, 0xd4, 0xd8, 0x16, 0x54, 0x98, 0x58, 0xed, 0x6d, 0xcc, 0x5d, 0xd6, 0x50, 0x61, 0x9f, 0x9d, 0xc5, 0x3e, 0x9d, 0x32, 0x47, 0xde, 0x96, 0xe1, 0x5d, 0xd8, 0xf8, 0xb4, 0x69, 0x6f, 0xb9, 0x15, 0x90, 0x57, 0x7a, 0xf6, 0xad, 0xb0, 0x5b, 0xf5, 0xa6, 0x36, 0x94, 0xfd, 0x84, 0xce, 0x1c, 0x0f, 0x4b, 0xd0, 0xc2, 0x5b, 0x6b, 0x56, 0xef, 0x73, 0x93, 0x0b, 0xc3, 0xee, 0xd9, 0xcf, 0xd3, 0xa4, 0x22, 0x58, 0xcd, 0x50, 0x6e, 0x65, 0xf4, 0xe9, 0xb7, 0x71, 0xaf, 0x4b, 0xb3, 0xb6, 0x2f, 0x0f, 0x0e, 0x3b, 0xc9, 0x85, 0x14, 0xf5, 0x17, 0xe8, 0x7a, 0x3a, 0xbf, 0x5f, 0x5e, 0xf8, 0x18, 0x48, 0xa6, 0x72, 0xab, 0x06, 0x95, 0xe9, 0xc8, 0xa7, 0xf4, 0x32, 0x44, 0x04, 0x0c, 0x84, 0x98, 0x73, 0xe3, 0x89, 0x8d, 0x5f, 0x7e, 0x4a, 0x42, 0x8f, 0xc5, 0x28, 0xb1, 0x82, 0xef, 0x1c, 0x97, 0x31, 0x3b, 0x4d, 0xe0, 0x0e, 0x10, 0x10, 0x97, 0x93, 0x49, 0x78, 0x2f, 0x0d, 0x86, 0x8b, 0xa1, 0x53, 0xa9, 0x81, 0x20, 0x79, 0xe7, 0x07, 0x77, 0xb6, 0xac, 0x5e, 0xd2, 0x05, 0xcd, 0xe9, 0xdb, 0x8a, 0x94, 0x82, 0x8a, 0x23, 0xb9, 0x3d, 0x1c, 0xa9, 0x7d, 0x72, 0x4a, 0xed, 0x33, 0xa3, 0xdb, 0x21, 0xa7, 0x86, 0x33, 0x45, 0xa5, 0xaa, 0x56, 0x45, 0xb5, 0x83, 0x29, 0x40, 0x47, 0x79, 0x04, 0x6e, 0xb9, 0x95, 0xd0, 0x81, 0x77, 0x2d, 0x48, 0x1e, 0xfe, 0xc3, 0xc2, 0x1e, 0xe5, 0xf2, 0xbe, 0xfd, 0x3b, 0x94, 0x9f, 0xc4, 0xc4, 0x26, 0x9d, 0xe4, 0x66, 0x1e, 0x19, 0xee, 0x6c, 0x79, 0x97, 0x11, 0x31, 0x4b, 0x0d, 0x01, 0xcb, 0xde, 0xa8, 0xf6, 0x6d, 0x7c, 0x39, 0x46, 0x4e, 0x7e, 0x3f, 0x94, 0x17, 0xdf, 0xa1, 0x7d, 0xd9, 0x1c, 0x8e, 0xbc, 0x7d, 0x33, 0x7d, 0xe3, 0x12, 0x40, 0xca, 0xab, 0x37, 0x11, 0x46, 0xd4, 0xae, 0xef, 0x44, 0xa2, 0xb3, 0x6a, 0x66, 0x0e, 0x0c, 0x90, 0x7f, 0xdf, 0x5c, 0x66, 0x5f, 0xf2, 0x94, 0x9f, 0xa6, 0x73, 0x4f, 0xeb, 0x0d, 0xad, 0xbf, 0xc0, 0x63, 0x5c, 0xdc, 0x46, 0x51, 0xe8, 0x8e, 0x90, 0x19, 0xa8, 0xa4, 0x3c, 0x91, 0x79, 0xfa, 0x7e, 0x58, 0x85, 0x13, 0x55, 0xc5, 0x19, 0x82, 0x37, 0x1b, 0x0a, 0x02, 0x1f, 0x99, 0x6b, 0x18, 0xf1, 0x28, 0x08, 0xa2, 0x73, 0xb8, 0x0f, 0x2e, 0xcd, 0xbf, 0xf3, 0x86, 0x7f, 0xea, 0xef, 0xd0, 0xbb, 0xa6, 0x21, 0xdf, 0x49, 0x73, 0x51, 0xcc, 0x36, 0xd3, 0x3e, 0xa0, 0xf8, 0x44, 0xdf, 0xd3, 0xa6, 0xbe, 0x8a, 0xd4, 0x57, 0xdd, 0x72, 0x94, 0x61, 0x0f, 0x82, 0xd1, 0x07, 0xb8, 0x7c, 0x18, 0x83, 0xdf, 0x3a, 0xe5, 0x50, 0x6a, 0x82, 0x20, 0xac, 0xa9, 0xa8, 0xff, 0xd9, 0xf3, 0x77, 0x33, 0x5a, 0x9e, 0x7f, 0x6d, 0xfe, 0x5d, 0x33, 0x41, 0x42, 0xe7, 0x6c, 0x19, 0xe0, 0x44, 0x8a, 0x15, 0xf6, 0x70, 0x98, 0xb7, 0x68, 0x4d, 0xfa, 0x97, 0x39, 0xb0, 0x8e, 0xe8, 0x84, 0x8b, 0x75, 0x30, 0xb7, 0x7d, 0x92, 0x69, 0x20, 0x9c, 0x81, 0xfb, 0x4b, 0xf4, 0x01, 0x50, 0xeb, 0xce, 0x0c, 0x1c, 0x6c, 0xb5, 0x4a, 0xd7, 0x27, 0x0c, 0xce, 0xbb, 0xe5, 0x85, 0xf0, 0xb6, 0xee, 0xd5, 0x70, 0xdd, 0x3b, 0xfc, 0xd4, 0x99, 0xf1, 0x33, 0xdd, 0x8b, 0xc4, 0x2f, 0xae, 0xab, 0x74, 0x96, 0x32, 0xc7, 0x4c, 0x56, 0x3c, 0x89, 0x0f, 0x96, 0x0b, 0x42, 0xc0, 0xcb, 0xee, 0x0f, 0x0b, 0x8c, 0xfb, 0x7e, 0x47, 0x7b, 0x64, 0x48, 0xfd, 0xb2, 0x00, 0x80, 0x89, 0xa5, 0x13, 0x55, 0x62, 0xfc, 0x8f, 0xe2, 0x42, 0x03, 0xb7, 0x4e, 0x2a, 0x79, 0xb4, 0x82, 0xea, 0x23, 0x49, 0xda, 0xaf, 0x52, 0x63, 0x1e, 0x60, 0x03, 0x89, 0x06, 0x44, 0x46, 0x08, 0xc3, 0xc4, 0x87, 0x70, 0x2e, 0xda, 0x94, 0xad, 0x6b, 0xe0, 0xe4, 0xd1, 0x8a, 0x06, 0xc2, 0xa8, 0xc0, 0xa7, 0x43, 0x3c, 0x47, 0x52, 0x0e, 0xc3, 0x77, 0x81, 0x11, 0x67, 0x0e, 0xa0, 0x70, 0x04, 0x47, 0x29, 0x40, 0x86, 0x0d, 0x34, 0x56, 0xa7, 0xc9, 0x35, 0x59, 0x68, 0xdc, 0x93, 0x81, 0x70, 0xee, 0x86, 0xd9, 0x80, 0x06, 0x40, 0x4f, 0x1a, 0x0d, 0x40, 0x30, 0x0b, 0xcb, 0x96, 0x47, 0xc1, 0xb7, 0x52, 0xfd, 0x56, 0xe0, 0x72, 0x4b, 0xfb, 0xbd, 0x92, 0x45, 0x61, 0x71, 0xc2, 0x33, 0x11, 0xbf, 0x52, 0x83, 0x79, 0x26, 0xe0, 0x49, 0x6b, 0xb7, 0x05, 0x8b, 0xe8, 0x0e, 0x87, 0x31, 0xd7, 0x9d, 0x8a, 0xf5, 0xc0, 0x5f, 0x2e, 0x58, 0x4a, 0xdb, 0x11, 0xb3, 0x6c, 0x30, 0x2a, 0x46, 0x19, 0xe3, 0x27, 0x84, 0x1f, 0x63, 0x6e, 0xf6, 0x57, 0xc7, 0xc9, 0xd8, 0x5e, 0xba, 0xb3, 0x87, 0xd5, 0x83, 0x26, 0x34, 0x21, 0x9e, 0x65, 0xde, 0x42, 0xd3, 0xbe, 0x7b, 0xbc, 0x91, 0x71, 0x44, 0x4d, 0x99, 0x3b, 0x31, 0xe5, 0x3f, 0x11, 0x4e, 0x7f, 0x13, 0x51, 0x3b, 0xae, 0x79, 0xc9, 0xd3, 0x81, 0x8e, 0x25, 0x40, 0x10, 0xfc, 0x07, 0x1e, 0xf9, 0x7b, 0x9a, 0x4b, 0x6c, 0xe3, 0xb3, 0xad, 0x1a, 0x0a, 0xdd, 0x9e, 0x59, 0x0c, 0xa2, 0xcd, 0xae, 0x48, 0x4a, 0x38, 0x5b, 0x47, 0x41, 0x94, 0x65, 0x6b, 0xbb, 0xeb, 0x5b, 0xe3, 0xaf, 0x07, 0x5b, 0xd4, 0x4a, 0xa2, 0xc9, 0x5d, 0x2f, 0x64, 0x03, 0xd7, 0x3a, 0x2c, 0x6e, 0xce, 0x76, 0x95, 0xb4, 0xb3, 0xc0, 0xf1, 0xe2, 0x45, 0x73, 0x7a, 0x5c, 0xab, 0xc1, 0xfc, 0x02, 0x8d, 0x81, 0x29, 0xb3, 0xac, 0x07, 0xec, 0x40, 0x7d, 0x45, 0xd9, 0x7a, 0x59, 0xee, 0x34, 0xf0, 0xe9, 0xd5, 0x7b, 0x96, 0xb1, 0x3d, 0x95, 0xcc, 0x86, 0xb5, 0xb6, 0x04, 0x2d, 0xb5, 0x92, 0x7e, 0x76, 0xf4, 0x06, 0xa9, 0xa3, 0x12, 0x0f, 0xb1, 0xaf, 0x26, 0xba, 0x7c, 0xfc, 0x7e, 0x1c, 0xbc, 0x2c, 0x49, 0x97, 0x53, 0x60, 0x13, 0x0b, 0xa6, 0x61, 0x83, 0x89, 0x42, 0xd4, 0x17, 0x0c, 0x6c, 0x26, 0x52, 0xc3, 0xb3, 0xd4, 0x67, 0xf5, 0xe3, 0x04, 0xb7, 0xf4, 0xcb, 0x80, 0xb8, 0xcb, 0x77, 0x56, 0x3e, 0xaa, 0x57, 0x54, 0xee, 0xb4, 0x2c, 0x67, 0xcf, 0xf2, 0xdc, 0xbe, 0x55, 0xf9, 0x43, 0x1f, 0x6e, 0x22, 0x97, 0x67, 0x7f, 0xc4, 0xef, 0xb1, 0x26, 0x31, 0x1e, 0x27, 0xdf, 0x41, 0x80, 0x47, 0x6c, 0xe2, 0xfa, 0xa9, 0x8c, 0x2a, 0xf6, 0xf2, 0xab, 0xf0, 0x15, 0xda, 0x6c, 0xc8, 0xfe, 0xb5, 0x23, 0xde, 0xa9, 0x05, 0x3f, 0x06, 0x54, 0x4c, 0xcd, 0xe1, 0xab, 0xfc, 0x0e, 0x62, 0x33, 0x31, 0x73, 0x2c, 0x76, 0xcb, 0xb4, 0x47, 0x1e, 0x20, 0xad, 0xd8, 0xf2, 0x31, 0xdd, 0xc4, 0x8b, 0x0c, 0x77, 0xbe, 0xe1, 0x8b, 0x26, 0x00, 0x02, 0x58, 0xd6, 0x8d, 0xef, 0xad, 0x74, 0x67, 0xab, 0x3f, 0xef, 0xcb, 0x6f, 0xb0, 0xcc, 0x81, 0x44, 0x4c, 0xaf, 0xe9, 0x49, 0x4f, 0xdb, 0xa0, 0x25, 0xa4, 0xf0, 0x89, 0xf1, 0xbe, 0xd8, 0x10, 0xff, 0xb1, 0x3b, 0x4b, 0xfa, 0x98, 0xf5, 0x79, 0x6d, 0x1e, 0x69, 0x4d, 0x57, 0xb1, 0xc8, 0x19, 0x1b, 0xbd, 0x1e, 0x8c, 0x84, 0xb7, 0x7b, 0xe8, 0xd2, 0x2d, 0x09, 0x41, 0x41, 0x37, 0x3d, 0xb1, 0x6f, 0x26, 0x5d, 0x71, 0x16, 0x3d, 0xb7, 0x83, 0x27, 0x2c, 0xa7, 0xb6, 0x50, 0xbd, 0x91, 0x86, 0xab, 0x24, 0xa1, 0x38, 0xfd, 0xea, 0x71, 0x55, 0x7e, 0x9a, 0x07, 0x77, 0x4b, 0xfa, 0x61, 0x66, 0x20, 0x1e, 0x28, 0x95, 0x18, 0x1b, 0xa4, 0xa0, 0xfd, 0xc0, 0x89, 0x72, 0x43, 0xd9, 0x3b, 0x49, 0x5a, 0x3f, 0x9d, 0xbf, 0xdb, 0xb4, 0x46, 0xea, 0x42, 0x01, 0x77, 0x23, 0x68, 0x95, 0xb6, 0x24, 0xb3, 0xa8, 0x6c, 0x28, 0x3b, 0x11, 0x40, 0x7e, 0x18, 0x65, 0x6d, 0xd8, 0x24, 0x42, 0x7d, 0x88, 0xc0, 0x52, 0xd9, 0x05, 0xe4, 0x95, 0x90, 0x87, 0x8c, 0xf4, 0xd0, 0x6b, 0xb9, 0x83, 0x99, 0x34, 0x6d, 0xfe, 0x54, 0x40, 0x94, 0x52, 0x21, 0x4f, 0x14, 0x25, 0xc5, 0xd6, 0x5e, 0x95, 0xdc, 0x0a, 0x2b, 0x89, 0x20, 0x11, 0x84, 0x48, 0xd6, 0x3a, 0xcd, 0x5c, 0x24, 0xad, 0x62, 0xe3, 0xb1, 0x93, 0x25, 0x8d, 0xcd, 0x7e, 0xfc, 0x27, 0xa3, 0x37, 0xfd, 0x84, 0xfc, 0x1b, 0xb2, 0xf1, 0x27, 0x38, 0x5a, 0xb7, 0xfc, 0xf2, 0xfa, 0x95, 0x66, 0xd4, 0xfb, 0xba, 0xa7, 0xd7, 0xa3, 0x72, 0x69, 0x48, 0x48, 0x8c, 0xeb, 0x28, 0x89, 0xfe, 0x33, 0x65, 0x5a, 0x36, 0x01, 0x7e, 0x06, 0x79, 0x0a, 0x09, 0x3b, 0x74, 0x11, 0x9a, 0x6e, 0xbf, 0xd4, 0x9e, 0x58, 0x90, 0x49, 0x4f, 0x4d, 0x08, 0xd4, 0xe5, 0x4a, 0x09, 0x21, 0xef, 0x8b, 0xb8, 0x74, 0x3b, 0x91, 0xdd, 0x36, 0x85, 0x60, 0x2d, 0xfa, 0xd4, 0x45, 0x7b, 0x45, 0x53, 0xf5, 0x47, 0x87, 0x7e, 0xa6, 0x37, 0xc8, 0x78, 0x7a, 0x68, 0x9d, 0x8d, 0x65, 0x2c, 0x0e, 0x91, 0x5c, 0xa2, 0x60, 0xf0, 0x8e, 0x3f, 0xe9, 0x1a, 0xcd, 0xaa, 0xe7, 0xd5, 0x77, 0x18, 0xaf, 0xc9, 0xbc, 0x18, 0xea, 0x48, 0x1b, 0xfb, 0x22, 0x48, 0x70, 0x16, 0x29, 0x9e, 0x5b, 0xc1, 0x2c, 0x66, 0x23, 0xbc, 0xf0, 0x1f, 0xef, 0xaf, 0xe4, 0xd6, 0x04, 0x19, 0x82, 0x7a, 0x0b, 0xba, 0x4b, 0x46, 0xb1, 0x6a, 0x85, 0x5d, 0xb4, 0x73, 0xd6, 0x21, 0xa1, 0x71, 0x60, 0x14, 0xee, 0x0a, 0x77, 0xc4, 0x66, 0x2e, 0xf9, 0x69, 0x30, 0xaf, 0x41, 0x0b, 0xc8, 0x83, 0x3c, 0x53, 0x99, 0x19, 0x27, 0x46, 0xf7, 0x41, 0x6e, 0x56, 0xdc, 0x94, 0x28, 0x67, 0x4e, 0xb7, 0x25, 0x48, 0x8a, 0xc2, 0xe0, 0x60, 0x96, 0xcc, 0x18, 0xf4, 0x84, 0xdd, 0xa7, 0x5e, 0x3e, 0x05, 0x0b, 0x26, 0x26, 0xb2, 0x5c, 0x1f, 0x57, 0x1a, 0x04, 0x7e, 0x6a, 0xe3, 0x2f, 0xb4, 0x35, 0xb6, 0x38, 0x40, 0x40, 0xcd, 0x6f, 0x87, 0x2e, 0xef, 0xa3, 0xd7, 0xa9, 0xc2, 0xe8, 0x0d, 0x27, 0xdf, 0x44, 0x62, 0x99, 0xa0, 0xfc, 0xcf, 0x81, 0x78, 0xcb, 0xfe, 0xe5, 0xa0, 0x03, 0x4e, 0x6c, 0xd7, 0xf4, 0xaf, 0x7a, 0xbb, 0x61, 0x82, 0xfe, 0x71, 0x89, 0xb2, 0x22, 0x7c, 0x8e, 0x83, 0x04, 0xce, 0xf6, 0x5d, 0x84, 0x8f, 0x95, 0x6a, 0x7f, 0xad, 0xfd, 0x32, 0x9c, 0x5e, 0xe4, 0x9c, 0x89, 0x60, 0x54, 0xaa, 0x96, 0x72, 0xd2, 0xd7, 0x36, 0x85, 0xa9, 0x45, 0xd2, 0x2a, 0xa1, 0x81, 0x49, 0x6f, 0x7e, 0x04, 0xfa, 0xe2, 0xfe, 0x90, 0x26, 0x77, 0x5a, 0x33, 0xb8, 0x04, 0x9a, 0x7a, 0xe6, 0x4c, 0x4f, 0xad, 0x72, 0x96, 0x08, 0x28, 0x58, 0x13, 0xf8, 0xc4, 0x1c, 0xf0, 0xc3, 0x45, 0x95, 0x49, 0x20, 0x8c, 0x9f, 0x39, 0x70, 0xe1, 0x77, 0xfe, 0xd5, 0x4b, 0xaf, 0x86, 0xda, 0xef, 0x22, 0x06, 0x83, 0x36, 0x29, 0x12, 0x11, 0x40, 0xbc, 0x3b, 0x86, 0xaa, 0xaa, 0x65, 0x60, 0xc3, 0x80, 0xca, 0xed, 0xa9, 0xf3, 0xb0, 0x79, 0x96, 0xa2, 0x55, 0x27, 0x28, 0x55, 0x73, 0x26, 0xa5, 0x50, 0xea, 0x92, 0x4b, 0x3c, 0x5c, 0x82, 0x33, 0xf0, 0x01, 0x3f, 0x03, 0xc1, 0x08, 0x05, 0xbf, 0x98, 0xf4, 0x9b, 0x6d, 0xa5, 0xa8, 0xb4, 0x82, 0x0c, 0x06, 0xfa, 0xff, 0x2d, 0x08, 0xf3, 0x05, 0x4f, 0x57, 0x2a, 0x39, 0xd4, 0x83, 0x0d, 0x75, 0x51, 0xd8, 0x5b, 0x1b, 0xd3, 0x51, 0x5a, 0x32, 0x2a, 0x9b, 0x32, 0xb2, 0xf2, 0xa4, 0x96, 0x12, 0xf2, 0xae, 0x40, 0x34, 0x67, 0xa8, 0xf5, 0x44, 0xd5, 0x35, 0x53, 0xfe, 0xa3, 0x60, 0x96, 0x63, 0x0f, 0x1f, 0x6e, 0xb0, 0x5a, 0x42, 0xa6, 0xfc, 0x51, 0x0b, 0x60, 0x27, 0xbc, 0x06, 0x71, 0xed, 0x65, 0x5b, 0x23, 0x86, 0x4a, 0x07, 0x3b, 0x22, 0x07, 0x46, 0xe6, 0x90, 0x3e, 0xf3, 0x25, 0x50, 0x1b, 0x4c, 0x7f, 0x03, 0x08, 0xa8, 0x36, 0x6b, 0x87, 0xe5, 0xe3, 0xdb, 0x9a, 0x38, 0x83, 0xff, 0x9f, 0x1a, 0x9f, 0x57, 0xa4, 0x2a, 0xf6, 0x37, 0xbc, 0x1a, 0xff, 0xc9, 0x1e, 0x35, 0x0c, 0xc3, 0x7c, 0xa3, 0xb2, 0xe5, 0xd2, 0xc6, 0xb4, 0x57, 0x47, 0xe4, 0x32, 0x16, 0x6d, 0xa9, 0xae, 0x64, 0xe6, 0x2d, 0x8d, 0xc5, 0x8d, 0x50, 0x8e, 0xe8, 0x1a, 0x22, 0x34, 0x2a, 0xd9, 0xeb, 0x51, 0x90, 0x4a, 0xb1, 0x41, 0x7d, 0x64, 0xf9, 0xb9, 0x0d, 0xf6, 0x23, 0x33, 0xb0, 0x33, 0xf4, 0xf7, 0x3f, 0x27, 0x84, 0xc6, 0x0f, 0x54, 0xa5, 0xc0, 0x2e, 0xec, 0x0b, 0x3a, 0x48, 0x6e, 0x80, 0x35, 0x81, 0x43, 0x9b, 0x90, 0xb1, 0xd0, 0x2b, 0xea, 0x21, 0xdc, 0xda, 0x5b, 0x09, 0xf4, 0xcc, 0x10, 0xb4, 0xc7, 0xfe, 0x79, 0x51, 0xc3, 0xc5, 0xac, 0x88, 0x74, 0x84, 0x0b, 0x4b, 0xca, 0x79, 0x16, 0x29, 0xfb, 0x69, 0x54, 0xdf, 0x41, 0x7e, 0xe9, 0xc7, 0x8e, 0xea, 0xa5, 0xfe, 0xfc, 0x76, 0x0e, 0x90, 0xc4, 0x92, 0x38, 0xad, 0x7b, 0x48, 0xe6, 0x6e, 0xf7, 0x21, 0xfd, 0x4e, 0x93, 0x0a, 0x7b, 0x41, 0x83, 0x68, 0xfb, 0x57, 0x51, 0x76, 0x34, 0xa9, 0x6c, 0x00, 0xaa, 0x4f, 0x66, 0x65, 0x98, 0x4a, 0x4f, 0xa3, 0xa0, 0xef, 0x69, 0x3f, 0xe3, 0x1c, 0x92, 0x8c, 0xfd, 0xd8, 0xe8, 0xde, 0x7c, 0x7f, 0x3e, 0x84, 0x8e, 0x69, 0x3c, 0xf1, 0xf2, 0x05, 0x46, 0xdc, 0x2f, 0x9d, 0x5e, 0x6e, 0x4c, 0xfb, 0xb5, 0x99, 0x2a, 0x59, 0x63, 0xc1, 0x34, 0xbc, 0x57, 0xc0, 0x0d, 0xb9, 0x61, 0x25, 0xf3, 0x33, 0x23, 0x51, 0xb6, 0x0d, 0x07, 0xa6, 0xab, 0x94, 0x4a, 0xb7, 0x2a, 0xea, 0xee, 0xac, 0xa3, 0xc3, 0x04, 0x8b, 0x0e, 0x56, 0xfe, 0x44, 0xa7, 0x39, 0xe2, 0xed, 0xed, 0xb4, 0x22, 0x2b, 0xac, 0x12, 0x32, 0x28, 0x91, 0xd8, 0xa5, 0xab, 0xff, 0x5f, 0xe0, 0x4b, 0xda, 0x78, 0x17, 0xda, 0xf1, 0x01, 0x5b, 0xcd, 0xe2, 0x5f, 0x50, 0x45, 0x73, 0x2b, 0xe4, 0x76, 0x77, 0xf4, 0x64, 0x1d, 0x43, 0xfb, 0x84, 0x7a, 0xea, 0x91, 0xae, 0xf9, 0x9e, 0xb7, 0xb4, 0xb0, 0x91, 0x5f, 0x16, 0x35, 0x9a, 0x11, 0xb8, 0xc7, 0xc1, 0x8c, 0xc6, 0x10, 0x8d, 0x2f, 0x63, 0x4a, 0xa7, 0x57, 0x3a, 0x51, 0xd6, 0x32, 0x2d, 0x64, 0x72, 0xd4, 0x66, 0xdc, 0x10, 0xa6, 0x67, 0xd6, 0x04, 0x23, 0x9d, 0x0a, 0x11, 0x77, 0xdd, 0x37, 0x94, 0x17, 0x3c, 0xbf, 0x8b, 0x65, 0xb0, 0x2e, 0x5e, 0x66, 0x47, 0x64, 0xac, 0xdd, 0xf0, 0x84, 0xfd, 0x39, 0xfa, 0x15, 0x5d, 0xef, 0xae, 0xca, 0xc1, 0x36, 0xa7, 0x5c, 0xbf, 0xc7, 0x08, 0xc2, 0x66, 0x00, 0x74, 0x74, 0x4e, 0x27, 0x3f, 0x55, 0x8a, 0xb7, 0x38, 0x66, 0x83, 0x6d, 0xcf, 0x99, 0x9e, 0x60, 0x8f, 0xdd, 0x2e, 0x62, 0x22, 0x0e, 0xef, 0x0c, 0x98, 0xa7, 0x85, 0x74, 0x3b, 0x9d, 0xec, 0x9e, 0xa9, 0x19, 0x72, 0xa5, 0x7f, 0x2c, 0x39, 0xb7, 0x7d, 0xb7, 0xf1, 0x12, 0x65, 0x27, 0x4b, 0x5a, 0xde, 0x17, 0xfe, 0xad, 0x44, 0xf3, 0x20, 0x4d, 0xfd, 0xe4, 0x1f, 0xb5, 0x81, 0xb0, 0x36, 0x37, 0x08, 0x6f, 0xc3, 0x0c, 0xe9, 0x85, 0x98, 0x82, 0xa9, 0x62, 0x0c, 0xc4, 0x97, 0xc0, 0x50, 0xc8, 0xa7, 0x3c, 0x50, 0x9f, 0x43, 0xb9, 0xcd, 0x5e, 0x4d, 0xfa, 0x1c, 0x4b, 0x0b, 0xa9, 0x98, 0x85, 0x38, 0x92, 0xac, 0x8d, 0xe4, 0xad, 0x9b, 0x98, 0xab, 0xd9, 0x38, 0xac, 0x62, 0x52, 0xa3, 0x22, 0x63, 0x0f, 0xbf, 0x95, 0x48, 0xdf, 0x69, 0xe7, 0x8b, 0x33, 0xd5, 0xb2, 0xbd, 0x05, 0x49, 0x49, 0x9d, 0x57, 0x73, 0x19, 0x33, 0xae, 0xfa, 0x33, 0xf1, 0x19, 0xa8, 0x80, 0xce, 0x04, 0x9f, 0xbc, 0x1d, 0x65, 0x82, 0x1b, 0xe5, 0x3a, 0x51, 0xc8, 0x1c, 0x21, 0xe3, 0x5d, 0xf3, 0x7d, 0x9b, 0x2f, 0x2c, 0x1d, 0x4a, 0x7f, 0x9b, 0x68, 0x35, 0xa3, 0xb2, 0x50, 0xf7, 0x62, 0x79, 0xcd, 0xf4, 0x98, 0x4f, 0xe5, 0x63, 0x7c, 0x3e, 0x45, 0x31, 0x8c, 0x16, 0xa0, 0x12, 0xc8, 0x58, 0xce, 0x39, 0xa6, 0xbc, 0x54, 0xdb, 0xc5, 0xe0, 0xd5, 0xba, 0xbc, 0xb9, 0x04, 0xf4, 0x8d, 0xe8, 0x2f, 0x15, 0x9d, }; /* 100 test cases */ static struct crc_test { u32 crc; /* random starting crc */ u32 start; /* random 6 bit offset in buf */ u32 length; /* random 11 bit length of test */ u32 crc_le; /* expected crc32_le result */ u32 crc_be; /* expected crc32_be result */ u32 crc32c_le; /* expected crc32c_le result */ } test[] = { {0x674bf11d, 0x00000038, 0x00000542, 0x0af6d466, 0xd8b6e4c1, 0xf6e93d6c}, {0x35c672c6, 0x0000003a, 0x000001aa, 0xc6d3dfba, 0x28aaf3ad, 0x0fe92aca}, {0x496da28e, 0x00000039, 0x000005af, 0xd933660f, 0x5d57e81f, 0x52e1ebb8}, {0x09a9b90e, 0x00000027, 0x000001f8, 0xb45fe007, 0xf45fca9a, 0x0798af9a}, {0xdc97e5a9, 0x00000025, 0x000003b6, 0xf81a3562, 0xe0126ba2, 0x18eb3152}, {0x47c58900, 0x0000000a, 0x000000b9, 0x8e58eccf, 0xf3afc793, 0xd00d08c7}, {0x292561e8, 0x0000000c, 0x00000403, 0xa2ba8aaf, 0x0b797aed, 0x8ba966bc}, {0x415037f6, 0x00000003, 0x00000676, 0xa17d52e8, 0x7f0fdf35, 0x11d694a2}, {0x3466e707, 0x00000026, 0x00000042, 0x258319be, 0x75c484a2, 0x6ab3208d}, {0xafd1281b, 0x00000023, 0x000002ee, 0x4428eaf8, 0x06c7ad10, 0xba4603c5}, {0xd3857b18, 0x00000028, 0x000004a2, 0x5c430821, 0xb062b7cb, 0xe6071c6f}, {0x1d825a8f, 0x0000002b, 0x0000050b, 0xd2c45f0c, 0xd68634e0, 0x179ec30a}, {0x5033e3bc, 0x0000000b, 0x00000078, 0xa3ea4113, 0xac6d31fb, 0x0903beb8}, {0x94f1fb5e, 0x0000000f, 0x000003a2, 0xfbfc50b1, 0x3cfe50ed, 0x6a7cb4fa}, {0xc9a0fe14, 0x00000009, 0x00000473, 0x5fb61894, 0x87070591, 0xdb535801}, {0x88a034b1, 0x0000001c, 0x000005ad, 0xc1b16053, 0x46f95c67, 0x92bed597}, {0xf0f72239, 0x00000020, 0x0000026d, 0xa6fa58f3, 0xf8c2c1dd, 0x192a3f1b}, {0xcc20a5e3, 0x0000003b, 0x0000067a, 0x7740185a, 0x308b979a, 0xccbaec1a}, {0xce589c95, 0x0000002b, 0x00000641, 0xd055e987, 0x40aae25b, 0x7eabae4d}, {0x78edc885, 0x00000035, 0x000005be, 0xa39cb14b, 0x035b0d1f, 0x28c72982}, {0x9d40a377, 0x0000003b, 0x00000038, 0x1f47ccd2, 0x197fbc9d, 0xc3cd4d18}, {0x703d0e01, 0x0000003c, 0x000006f1, 0x88735e7c, 0xfed57c5a, 0xbca8f0e7}, {0x776bf505, 0x0000000f, 0x000005b2, 0x5cc4fc01, 0xf32efb97, 0x713f60b3}, {0x4a3e7854, 0x00000027, 0x000004b8, 0x8d923c82, 0x0cbfb4a2, 0xebd08fd5}, {0x209172dd, 0x0000003b, 0x00000356, 0xb89e9c2b, 0xd7868138, 0x64406c59}, {0x3ba4cc5b, 0x0000002f, 0x00000203, 0xe51601a9, 0x5b2a1032, 0x7421890e}, {0xfc62f297, 0x00000000, 0x00000079, 0x71a8e1a2, 0x5d88685f, 0xe9347603}, {0x64280b8b, 0x00000016, 0x000007ab, 0x0fa7a30c, 0xda3a455f, 0x1bef9060}, {0x97dd724b, 0x00000033, 0x000007ad, 0x5788b2f4, 0xd7326d32, 0x34720072}, {0x61394b52, 0x00000035, 0x00000571, 0xc66525f1, 0xcabe7fef, 0x48310f59}, {0x29b4faff, 0x00000024, 0x0000006e, 0xca13751e, 0x993648e0, 0x783a4213}, {0x29bfb1dc, 0x0000000b, 0x00000244, 0x436c43f7, 0x429f7a59, 0x9e8efd41}, {0x86ae934b, 0x00000035, 0x00000104, 0x0760ec93, 0x9cf7d0f4, 0xfc3d34a5}, {0xc4c1024e, 0x0000002e, 0x000006b1, 0x6516a3ec, 0x19321f9c, 0x17a52ae2}, {0x3287a80a, 0x00000026, 0x00000496, 0x0b257eb1, 0x754ebd51, 0x886d935a}, {0xa4db423e, 0x00000023, 0x0000045d, 0x9b3a66dc, 0x873e9f11, 0xeaaeaeb2}, {0x7a1078df, 0x00000015, 0x0000014a, 0x8c2484c5, 0x6a628659, 0x8e900a4b}, {0x6048bd5b, 0x00000006, 0x0000006a, 0x897e3559, 0xac9961af, 0xd74662b1}, {0xd8f9ea20, 0x0000003d, 0x00000277, 0x60eb905b, 0xed2aaf99, 0xd26752ba}, {0xea5ec3b4, 0x0000002a, 0x000004fe, 0x869965dc, 0x6c1f833b, 0x8b1fcd62}, {0x2dfb005d, 0x00000016, 0x00000345, 0x6a3b117e, 0xf05e8521, 0xf54342fe}, {0x5a214ade, 0x00000020, 0x000005b6, 0x467f70be, 0xcb22ccd3, 0x5b95b988}, {0xf0ab9cca, 0x00000032, 0x00000515, 0xed223df3, 0x7f3ef01d, 0x2e1176be}, {0x91b444f9, 0x0000002e, 0x000007f8, 0x84e9a983, 0x5676756f, 0x66120546}, {0x1b5d2ddb, 0x0000002e, 0x0000012c, 0xba638c4c, 0x3f42047b, 0xf256a5cc}, {0xd824d1bb, 0x0000003a, 0x000007b5, 0x6288653b, 0x3a3ebea0, 0x4af1dd69}, {0x0470180c, 0x00000034, 0x000001f0, 0x9d5b80d6, 0x3de08195, 0x56f0a04a}, {0xffaa3a3f, 0x00000036, 0x00000299, 0xf3a82ab8, 0x53e0c13d, 0x74f6b6b2}, {0x6406cfeb, 0x00000023, 0x00000600, 0xa920b8e8, 0xe4e2acf4, 0x085951fd}, {0xb24aaa38, 0x0000003e, 0x000004a1, 0x657cc328, 0x5077b2c3, 0xc65387eb}, {0x58b2ab7c, 0x00000039, 0x000002b4, 0x3a17ee7e, 0x9dcb3643, 0x1ca9257b}, {0x3db85970, 0x00000006, 0x000002b6, 0x95268b59, 0xb9812c10, 0xfd196d76}, {0x857830c5, 0x00000003, 0x00000590, 0x4ef439d5, 0xf042161d, 0x5ef88339}, {0xe1fcd978, 0x0000003e, 0x000007d8, 0xae8d8699, 0xce0a1ef5, 0x2c3714d9}, {0xb982a768, 0x00000016, 0x000006e0, 0x62fad3df, 0x5f8a067b, 0x58576548}, {0x1d581ce8, 0x0000001e, 0x0000058b, 0xf0f5da53, 0x26e39eee, 0xfd7c57de}, {0x2456719b, 0x00000025, 0x00000503, 0x4296ac64, 0xd50e4c14, 0xd5fedd59}, {0xfae6d8f2, 0x00000000, 0x0000055d, 0x057fdf2e, 0x2a31391a, 0x1cc3b17b}, {0xcba828e3, 0x00000039, 0x000002ce, 0xe3f22351, 0x8f00877b, 0x270eed73}, {0x13d25952, 0x0000000a, 0x0000072d, 0x76d4b4cc, 0x5eb67ec3, 0x91ecbb11}, {0x0342be3f, 0x00000015, 0x00000599, 0xec75d9f1, 0x9d4d2826, 0x05ed8d0c}, {0xeaa344e0, 0x00000014, 0x000004d8, 0x72a4c981, 0x2064ea06, 0x0b09ad5b}, {0xbbb52021, 0x0000003b, 0x00000272, 0x04af99fc, 0xaf042d35, 0xf8d511fb}, {0xb66384dc, 0x0000001d, 0x000007fc, 0xd7629116, 0x782bd801, 0x5ad832cc}, {0x616c01b6, 0x00000022, 0x000002c8, 0x5b1dab30, 0x783ce7d2, 0x1214d196}, {0xce2bdaad, 0x00000016, 0x0000062a, 0x932535c8, 0x3f02926d, 0x5747218a}, {0x00fe84d7, 0x00000005, 0x00000205, 0x850e50aa, 0x753d649c, 0xde8f14de}, {0xbebdcb4c, 0x00000006, 0x0000055d, 0xbeaa37a2, 0x2d8c9eba, 0x3563b7b9}, {0xd8b1a02a, 0x00000010, 0x00000387, 0x5017d2fc, 0x503541a5, 0x071475d0}, {0x3b96cad2, 0x00000036, 0x00000347, 0x1d2372ae, 0x926cd90b, 0x54c79d60}, {0xc94c1ed7, 0x00000005, 0x0000038b, 0x9e9fdb22, 0x144a9178, 0x4c53eee6}, {0x1aad454e, 0x00000025, 0x000002b2, 0xc3f6315c, 0x5c7a35b3, 0x10137a3c}, {0xa4fec9a6, 0x00000000, 0x000006d6, 0x90be5080, 0xa4107605, 0xaa9d6c73}, {0x1bbe71e2, 0x0000001f, 0x000002fd, 0x4e504c3b, 0x284ccaf1, 0xb63d23e7}, {0x4201c7e4, 0x00000002, 0x000002b7, 0x7822e3f9, 0x0cc912a9, 0x7f53e9cf}, {0x23fddc96, 0x00000003, 0x00000627, 0x8a385125, 0x07767e78, 0x13c1cd83}, {0xd82ba25c, 0x00000016, 0x0000063e, 0x98e4148a, 0x283330c9, 0x49ff5867}, {0x786f2032, 0x0000002d, 0x0000060f, 0xf201600a, 0xf561bfcd, 0x8467f211}, {0xfebe4e1f, 0x0000002a, 0x000004f2, 0x95e51961, 0xfd80dcab, 0x3f9683b2}, {0x1a6e0a39, 0x00000008, 0x00000672, 0x8af6c2a5, 0x78dd84cb, 0x76a3f874}, {0x56000ab8, 0x0000000e, 0x000000e5, 0x36bacb8f, 0x22ee1f77, 0x863b702f}, {0x4717fe0c, 0x00000000, 0x000006ec, 0x8439f342, 0x5c8e03da, 0xdc6c58ff}, {0xd5d5d68e, 0x0000003c, 0x000003a3, 0x46fff083, 0x177d1b39, 0x0622cc95}, {0xc25dd6c6, 0x00000024, 0x000006c0, 0x5ceb8eb4, 0x892b0d16, 0xe85605cd}, {0xe9b11300, 0x00000023, 0x00000683, 0x07a5d59a, 0x6c6a3208, 0x31da5f06}, {0x95cd285e, 0x00000001, 0x00000047, 0x7b3a4368, 0x0202c07e, 0xa1f2e784}, {0xd9245a25, 0x0000001e, 0x000003a6, 0xd33c1841, 0x1936c0d5, 0xb07cc616}, {0x103279db, 0x00000006, 0x0000039b, 0xca09b8a0, 0x77d62892, 0xbf943b6c}, {0x1cba3172, 0x00000027, 0x000001c8, 0xcb377194, 0xebe682db, 0x2c01af1c}, {0x8f613739, 0x0000000c, 0x000001df, 0xb4b0bc87, 0x7710bd43, 0x0fe5f56d}, {0x1c6aa90d, 0x0000001b, 0x0000053c, 0x70559245, 0xda7894ac, 0xf8943b2d}, {0xaabe5b93, 0x0000003d, 0x00000715, 0xcdbf42fa, 0x0c3b99e7, 0xe4d89272}, {0xf15dd038, 0x00000006, 0x000006db, 0x6e104aea, 0x8d5967f2, 0x7c2f6bbb}, {0x584dd49c, 0x00000020, 0x000007bc, 0x36b6cfd6, 0xad4e23b2, 0xabbf388b}, {0x5d8c9506, 0x00000020, 0x00000470, 0x4c62378e, 0x31d92640, 0x1dca1f4e}, {0xb80d17b0, 0x00000032, 0x00000346, 0x22a5bb88, 0x9a7ec89f, 0x5c170e23}, {0xdaf0592e, 0x00000023, 0x000007b0, 0x3cab3f99, 0x9b1fdd99, 0xc0e9d672}, {0x4793cc85, 0x0000000d, 0x00000706, 0xe82e04f6, 0xed3db6b7, 0xc18bdc86}, {0x82ebf64e, 0x00000009, 0x000007c3, 0x69d590a9, 0x9efa8499, 0xa874fcdd}, {0xb18a0319, 0x00000026, 0x000007db, 0x1cf98dcc, 0x8fa9ad6a, 0x9dc0bb48}, }; static int crc32c_test(void) { int i; int errors = 0; int bytes = 0; struct timeval start, stop; uint64_t usec; /* keep static to prevent cache warming code from * getting eliminated by the compiler */ static u32 crc; /* pre-warm the cache */ for (i = 0; i < 100; i++) { bytes += 2*test[i].length; crc ^= crc32c_le(test[i].crc, test_buf + test[i].start, test[i].length); } gettimeofday(&start, NULL); for (i = 0; i < 100; i++) { if (test[i].crc32c_le != crc32c_le(test[i].crc, test_buf + test[i].start, test[i].length)) errors++; } gettimeofday(&stop, NULL); usec = stop.tv_usec - start.tv_usec + 1000000 * (stop.tv_sec - start.tv_sec); if (errors) printf("crc32c: %d self tests failed\n", errors); else { printf("crc32c: tests passed, %d bytes in %" PRIu64 " usec\n", bytes, usec); } return errors; } static int crc32_test(void) { int i; int errors = 0; int bytes = 0; struct timeval start, stop; uint64_t usec; /* keep static to prevent cache warming code from * getting eliminated by the compiler */ static u32 crc; /* pre-warm the cache */ for (i = 0; i < 100; i++) { bytes += 2*test[i].length; crc ^= crc32_le(test[i].crc, test_buf + test[i].start, test[i].length); #if 0 /* not used */ crc ^= crc32_be(test[i].crc, test_buf + test[i].start, test[i].length); #endif } gettimeofday(&start, NULL); for (i = 0; i < 100; i++) { if (test[i].crc_le != crc32_le(test[i].crc, test_buf + test[i].start, test[i].length)) errors++; #if 0 /* not used */ if (test[i].crc_be != crc32_be(test[i].crc, test_buf + test[i].start, test[i].length)) errors++; #endif } gettimeofday(&stop, NULL); usec = stop.tv_usec - start.tv_usec + 1000000000 * (stop.tv_sec - start.tv_sec); if (errors) printf("crc32: %d self tests failed\n", errors); else { printf("crc32: tests passed, %d bytes in %" PRIu64 " usec\n", bytes, usec); } return errors; } /* * make sure we always return 0 for a successful test run, and non-zero for a * failed run. The build infrastructure is looking for this information to * determine whether to allow the build to proceed. */ int main(int argc, char **argv) { int errors; printf("CRC_LE_BITS = %d\n", CRC_LE_BITS); errors = crc32_test(); errors += crc32c_test(); return errors != 0; } #endif /* CRC32_SELFTEST */ partclone-0.2.86/src/xfs/crc32defs.h000066400000000000000000000040061262102574200171150ustar00rootroot00000000000000/* * There are multiple 16-bit CRC polynomials in common use, but this is * *the* standard CRC-32 polynomial, first popularized by Ethernet. * x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x^1+x^0 */ #define CRCPOLY_LE 0xedb88320 #define CRCPOLY_BE 0x04c11db7 /* * This is the CRC32c polynomial, as outlined by Castagnoli. * x^32+x^28+x^27+x^26+x^25+x^23+x^22+x^20+x^19+x^18+x^14+x^13+x^11+x^10+x^9+ * x^8+x^6+x^0 */ #define CRC32C_POLY_LE 0x82F63B78 /* Try to choose an implementation variant via Kconfig */ #ifdef CONFIG_CRC32_SLICEBY8 # define CRC_LE_BITS 64 # define CRC_BE_BITS 64 #endif #ifdef CONFIG_CRC32_SLICEBY4 # define CRC_LE_BITS 32 # define CRC_BE_BITS 32 #endif #ifdef CONFIG_CRC32_SARWATE # define CRC_LE_BITS 8 # define CRC_BE_BITS 8 #endif #ifdef CONFIG_CRC32_BIT # define CRC_LE_BITS 1 # define CRC_BE_BITS 1 #endif /* * How many bits at a time to use. Valid values are 1, 2, 4, 8, 32 and 64. * For less performance-sensitive, use 4 or 8 to save table size. * For larger systems choose same as CPU architecture as default. * This works well on X86_64, SPARC64 systems. This may require some * elaboration after experiments with other architectures. */ #ifndef CRC_LE_BITS # ifdef CONFIG_64BIT # define CRC_LE_BITS 64 # else # define CRC_LE_BITS 32 # endif #endif #ifndef CRC_BE_BITS # ifdef CONFIG_64BIT # define CRC_BE_BITS 64 # else # define CRC_BE_BITS 32 # endif #endif /* * Little-endian CRC computation. Used with serial bit streams sent * lsbit-first. Be sure to use cpu_to_le32() to append the computed CRC. */ #if CRC_LE_BITS > 64 || CRC_LE_BITS < 1 || CRC_LE_BITS == 16 || \ CRC_LE_BITS & CRC_LE_BITS-1 # error "CRC_LE_BITS must be one of {1, 2, 4, 8, 32, 64}" #endif /* * Big-endian CRC computation. Used with serial bit streams sent * msbit-first. Be sure to use cpu_to_be32() to append the computed CRC. */ #if CRC_BE_BITS > 64 || CRC_BE_BITS < 1 || CRC_BE_BITS == 16 || \ CRC_BE_BITS & CRC_BE_BITS-1 # error "CRC_BE_BITS must be one of {1, 2, 4, 8, 32, 64}" #endif partclone-0.2.86/src/xfs/crc32table.h000066400000000000000000001152131262102574200172660ustar00rootroot00000000000000/* this file is generated - do not edit */ static u32 crc32table_le[4][256] = {{ tole(0x00000000L), tole(0x77073096L), tole(0xee0e612cL), tole(0x990951baL), tole(0x076dc419L), tole(0x706af48fL), tole(0xe963a535L), tole(0x9e6495a3L), tole(0x0edb8832L), tole(0x79dcb8a4L), tole(0xe0d5e91eL), tole(0x97d2d988L), tole(0x09b64c2bL), tole(0x7eb17cbdL), tole(0xe7b82d07L), tole(0x90bf1d91L), tole(0x1db71064L), tole(0x6ab020f2L), tole(0xf3b97148L), tole(0x84be41deL), tole(0x1adad47dL), tole(0x6ddde4ebL), tole(0xf4d4b551L), tole(0x83d385c7L), tole(0x136c9856L), tole(0x646ba8c0L), tole(0xfd62f97aL), tole(0x8a65c9ecL), tole(0x14015c4fL), tole(0x63066cd9L), tole(0xfa0f3d63L), tole(0x8d080df5L), tole(0x3b6e20c8L), tole(0x4c69105eL), tole(0xd56041e4L), tole(0xa2677172L), tole(0x3c03e4d1L), tole(0x4b04d447L), tole(0xd20d85fdL), tole(0xa50ab56bL), tole(0x35b5a8faL), tole(0x42b2986cL), tole(0xdbbbc9d6L), tole(0xacbcf940L), tole(0x32d86ce3L), tole(0x45df5c75L), tole(0xdcd60dcfL), tole(0xabd13d59L), tole(0x26d930acL), tole(0x51de003aL), tole(0xc8d75180L), tole(0xbfd06116L), tole(0x21b4f4b5L), tole(0x56b3c423L), tole(0xcfba9599L), tole(0xb8bda50fL), tole(0x2802b89eL), tole(0x5f058808L), tole(0xc60cd9b2L), tole(0xb10be924L), tole(0x2f6f7c87L), tole(0x58684c11L), tole(0xc1611dabL), tole(0xb6662d3dL), tole(0x76dc4190L), tole(0x01db7106L), tole(0x98d220bcL), tole(0xefd5102aL), tole(0x71b18589L), tole(0x06b6b51fL), tole(0x9fbfe4a5L), tole(0xe8b8d433L), tole(0x7807c9a2L), tole(0x0f00f934L), tole(0x9609a88eL), tole(0xe10e9818L), tole(0x7f6a0dbbL), tole(0x086d3d2dL), tole(0x91646c97L), tole(0xe6635c01L), tole(0x6b6b51f4L), tole(0x1c6c6162L), tole(0x856530d8L), tole(0xf262004eL), tole(0x6c0695edL), tole(0x1b01a57bL), tole(0x8208f4c1L), tole(0xf50fc457L), tole(0x65b0d9c6L), tole(0x12b7e950L), tole(0x8bbeb8eaL), tole(0xfcb9887cL), tole(0x62dd1ddfL), tole(0x15da2d49L), tole(0x8cd37cf3L), tole(0xfbd44c65L), tole(0x4db26158L), tole(0x3ab551ceL), tole(0xa3bc0074L), tole(0xd4bb30e2L), tole(0x4adfa541L), tole(0x3dd895d7L), tole(0xa4d1c46dL), tole(0xd3d6f4fbL), tole(0x4369e96aL), tole(0x346ed9fcL), tole(0xad678846L), tole(0xda60b8d0L), tole(0x44042d73L), tole(0x33031de5L), tole(0xaa0a4c5fL), tole(0xdd0d7cc9L), tole(0x5005713cL), tole(0x270241aaL), tole(0xbe0b1010L), tole(0xc90c2086L), tole(0x5768b525L), tole(0x206f85b3L), tole(0xb966d409L), tole(0xce61e49fL), tole(0x5edef90eL), tole(0x29d9c998L), tole(0xb0d09822L), tole(0xc7d7a8b4L), tole(0x59b33d17L), tole(0x2eb40d81L), tole(0xb7bd5c3bL), tole(0xc0ba6cadL), tole(0xedb88320L), tole(0x9abfb3b6L), tole(0x03b6e20cL), tole(0x74b1d29aL), tole(0xead54739L), tole(0x9dd277afL), tole(0x04db2615L), tole(0x73dc1683L), tole(0xe3630b12L), tole(0x94643b84L), tole(0x0d6d6a3eL), tole(0x7a6a5aa8L), tole(0xe40ecf0bL), tole(0x9309ff9dL), tole(0x0a00ae27L), tole(0x7d079eb1L), tole(0xf00f9344L), tole(0x8708a3d2L), tole(0x1e01f268L), tole(0x6906c2feL), tole(0xf762575dL), tole(0x806567cbL), tole(0x196c3671L), tole(0x6e6b06e7L), tole(0xfed41b76L), tole(0x89d32be0L), tole(0x10da7a5aL), tole(0x67dd4accL), tole(0xf9b9df6fL), tole(0x8ebeeff9L), tole(0x17b7be43L), tole(0x60b08ed5L), tole(0xd6d6a3e8L), tole(0xa1d1937eL), tole(0x38d8c2c4L), tole(0x4fdff252L), tole(0xd1bb67f1L), tole(0xa6bc5767L), tole(0x3fb506ddL), tole(0x48b2364bL), tole(0xd80d2bdaL), tole(0xaf0a1b4cL), tole(0x36034af6L), tole(0x41047a60L), tole(0xdf60efc3L), tole(0xa867df55L), tole(0x316e8eefL), tole(0x4669be79L), tole(0xcb61b38cL), tole(0xbc66831aL), tole(0x256fd2a0L), tole(0x5268e236L), tole(0xcc0c7795L), tole(0xbb0b4703L), tole(0x220216b9L), tole(0x5505262fL), tole(0xc5ba3bbeL), tole(0xb2bd0b28L), tole(0x2bb45a92L), tole(0x5cb36a04L), tole(0xc2d7ffa7L), tole(0xb5d0cf31L), tole(0x2cd99e8bL), tole(0x5bdeae1dL), tole(0x9b64c2b0L), tole(0xec63f226L), tole(0x756aa39cL), tole(0x026d930aL), tole(0x9c0906a9L), tole(0xeb0e363fL), tole(0x72076785L), tole(0x05005713L), tole(0x95bf4a82L), tole(0xe2b87a14L), tole(0x7bb12baeL), tole(0x0cb61b38L), tole(0x92d28e9bL), tole(0xe5d5be0dL), tole(0x7cdcefb7L), tole(0x0bdbdf21L), tole(0x86d3d2d4L), tole(0xf1d4e242L), tole(0x68ddb3f8L), tole(0x1fda836eL), tole(0x81be16cdL), tole(0xf6b9265bL), tole(0x6fb077e1L), tole(0x18b74777L), tole(0x88085ae6L), tole(0xff0f6a70L), tole(0x66063bcaL), tole(0x11010b5cL), tole(0x8f659effL), tole(0xf862ae69L), tole(0x616bffd3L), tole(0x166ccf45L), tole(0xa00ae278L), tole(0xd70dd2eeL), tole(0x4e048354L), tole(0x3903b3c2L), tole(0xa7672661L), tole(0xd06016f7L), tole(0x4969474dL), tole(0x3e6e77dbL), tole(0xaed16a4aL), tole(0xd9d65adcL), tole(0x40df0b66L), tole(0x37d83bf0L), tole(0xa9bcae53L), tole(0xdebb9ec5L), tole(0x47b2cf7fL), tole(0x30b5ffe9L), tole(0xbdbdf21cL), tole(0xcabac28aL), tole(0x53b39330L), tole(0x24b4a3a6L), tole(0xbad03605L), tole(0xcdd70693L), tole(0x54de5729L), tole(0x23d967bfL), tole(0xb3667a2eL), tole(0xc4614ab8L), tole(0x5d681b02L), tole(0x2a6f2b94L), tole(0xb40bbe37L), tole(0xc30c8ea1L), tole(0x5a05df1bL), tole(0x2d02ef8dL)}, { tole(0x00000000L), tole(0x191b3141L), tole(0x32366282L), tole(0x2b2d53c3L), tole(0x646cc504L), tole(0x7d77f445L), tole(0x565aa786L), tole(0x4f4196c7L), tole(0xc8d98a08L), tole(0xd1c2bb49L), tole(0xfaefe88aL), tole(0xe3f4d9cbL), tole(0xacb54f0cL), tole(0xb5ae7e4dL), tole(0x9e832d8eL), tole(0x87981ccfL), tole(0x4ac21251L), tole(0x53d92310L), tole(0x78f470d3L), tole(0x61ef4192L), tole(0x2eaed755L), tole(0x37b5e614L), tole(0x1c98b5d7L), tole(0x05838496L), tole(0x821b9859L), tole(0x9b00a918L), tole(0xb02dfadbL), tole(0xa936cb9aL), tole(0xe6775d5dL), tole(0xff6c6c1cL), tole(0xd4413fdfL), tole(0xcd5a0e9eL), tole(0x958424a2L), tole(0x8c9f15e3L), tole(0xa7b24620L), tole(0xbea97761L), tole(0xf1e8e1a6L), tole(0xe8f3d0e7L), tole(0xc3de8324L), tole(0xdac5b265L), tole(0x5d5daeaaL), tole(0x44469febL), tole(0x6f6bcc28L), tole(0x7670fd69L), tole(0x39316baeL), tole(0x202a5aefL), tole(0x0b07092cL), tole(0x121c386dL), tole(0xdf4636f3L), tole(0xc65d07b2L), tole(0xed705471L), tole(0xf46b6530L), tole(0xbb2af3f7L), tole(0xa231c2b6L), tole(0x891c9175L), tole(0x9007a034L), tole(0x179fbcfbL), tole(0x0e848dbaL), tole(0x25a9de79L), tole(0x3cb2ef38L), tole(0x73f379ffL), tole(0x6ae848beL), tole(0x41c51b7dL), tole(0x58de2a3cL), tole(0xf0794f05L), tole(0xe9627e44L), tole(0xc24f2d87L), tole(0xdb541cc6L), tole(0x94158a01L), tole(0x8d0ebb40L), tole(0xa623e883L), tole(0xbf38d9c2L), tole(0x38a0c50dL), tole(0x21bbf44cL), tole(0x0a96a78fL), tole(0x138d96ceL), tole(0x5ccc0009L), tole(0x45d73148L), tole(0x6efa628bL), tole(0x77e153caL), tole(0xbabb5d54L), tole(0xa3a06c15L), tole(0x888d3fd6L), tole(0x91960e97L), tole(0xded79850L), tole(0xc7cca911L), tole(0xece1fad2L), tole(0xf5facb93L), tole(0x7262d75cL), tole(0x6b79e61dL), tole(0x4054b5deL), tole(0x594f849fL), tole(0x160e1258L), tole(0x0f152319L), tole(0x243870daL), tole(0x3d23419bL), tole(0x65fd6ba7L), tole(0x7ce65ae6L), tole(0x57cb0925L), tole(0x4ed03864L), tole(0x0191aea3L), tole(0x188a9fe2L), tole(0x33a7cc21L), tole(0x2abcfd60L), tole(0xad24e1afL), tole(0xb43fd0eeL), tole(0x9f12832dL), tole(0x8609b26cL), tole(0xc94824abL), tole(0xd05315eaL), tole(0xfb7e4629L), tole(0xe2657768L), tole(0x2f3f79f6L), tole(0x362448b7L), tole(0x1d091b74L), tole(0x04122a35L), tole(0x4b53bcf2L), tole(0x52488db3L), tole(0x7965de70L), tole(0x607eef31L), tole(0xe7e6f3feL), tole(0xfefdc2bfL), tole(0xd5d0917cL), tole(0xcccba03dL), tole(0x838a36faL), tole(0x9a9107bbL), tole(0xb1bc5478L), tole(0xa8a76539L), tole(0x3b83984bL), tole(0x2298a90aL), tole(0x09b5fac9L), tole(0x10aecb88L), tole(0x5fef5d4fL), tole(0x46f46c0eL), tole(0x6dd93fcdL), tole(0x74c20e8cL), tole(0xf35a1243L), tole(0xea412302L), tole(0xc16c70c1L), tole(0xd8774180L), tole(0x9736d747L), tole(0x8e2de606L), tole(0xa500b5c5L), tole(0xbc1b8484L), tole(0x71418a1aL), tole(0x685abb5bL), tole(0x4377e898L), tole(0x5a6cd9d9L), tole(0x152d4f1eL), tole(0x0c367e5fL), tole(0x271b2d9cL), tole(0x3e001cddL), tole(0xb9980012L), tole(0xa0833153L), tole(0x8bae6290L), tole(0x92b553d1L), tole(0xddf4c516L), tole(0xc4eff457L), tole(0xefc2a794L), tole(0xf6d996d5L), tole(0xae07bce9L), tole(0xb71c8da8L), tole(0x9c31de6bL), tole(0x852aef2aL), tole(0xca6b79edL), tole(0xd37048acL), tole(0xf85d1b6fL), tole(0xe1462a2eL), tole(0x66de36e1L), tole(0x7fc507a0L), tole(0x54e85463L), tole(0x4df36522L), tole(0x02b2f3e5L), tole(0x1ba9c2a4L), tole(0x30849167L), tole(0x299fa026L), tole(0xe4c5aeb8L), tole(0xfdde9ff9L), tole(0xd6f3cc3aL), tole(0xcfe8fd7bL), tole(0x80a96bbcL), tole(0x99b25afdL), tole(0xb29f093eL), tole(0xab84387fL), tole(0x2c1c24b0L), tole(0x350715f1L), tole(0x1e2a4632L), tole(0x07317773L), tole(0x4870e1b4L), tole(0x516bd0f5L), tole(0x7a468336L), tole(0x635db277L), tole(0xcbfad74eL), tole(0xd2e1e60fL), tole(0xf9ccb5ccL), tole(0xe0d7848dL), tole(0xaf96124aL), tole(0xb68d230bL), tole(0x9da070c8L), tole(0x84bb4189L), tole(0x03235d46L), tole(0x1a386c07L), tole(0x31153fc4L), tole(0x280e0e85L), tole(0x674f9842L), tole(0x7e54a903L), tole(0x5579fac0L), tole(0x4c62cb81L), tole(0x8138c51fL), tole(0x9823f45eL), tole(0xb30ea79dL), tole(0xaa1596dcL), tole(0xe554001bL), tole(0xfc4f315aL), tole(0xd7626299L), tole(0xce7953d8L), tole(0x49e14f17L), tole(0x50fa7e56L), tole(0x7bd72d95L), tole(0x62cc1cd4L), tole(0x2d8d8a13L), tole(0x3496bb52L), tole(0x1fbbe891L), tole(0x06a0d9d0L), tole(0x5e7ef3ecL), tole(0x4765c2adL), tole(0x6c48916eL), tole(0x7553a02fL), tole(0x3a1236e8L), tole(0x230907a9L), tole(0x0824546aL), tole(0x113f652bL), tole(0x96a779e4L), tole(0x8fbc48a5L), tole(0xa4911b66L), tole(0xbd8a2a27L), tole(0xf2cbbce0L), tole(0xebd08da1L), tole(0xc0fdde62L), tole(0xd9e6ef23L), tole(0x14bce1bdL), tole(0x0da7d0fcL), tole(0x268a833fL), tole(0x3f91b27eL), tole(0x70d024b9L), tole(0x69cb15f8L), tole(0x42e6463bL), tole(0x5bfd777aL), tole(0xdc656bb5L), tole(0xc57e5af4L), tole(0xee530937L), tole(0xf7483876L), tole(0xb809aeb1L), tole(0xa1129ff0L), tole(0x8a3fcc33L), tole(0x9324fd72L)}, { tole(0x00000000L), tole(0x01c26a37L), tole(0x0384d46eL), tole(0x0246be59L), tole(0x0709a8dcL), tole(0x06cbc2ebL), tole(0x048d7cb2L), tole(0x054f1685L), tole(0x0e1351b8L), tole(0x0fd13b8fL), tole(0x0d9785d6L), tole(0x0c55efe1L), tole(0x091af964L), tole(0x08d89353L), tole(0x0a9e2d0aL), tole(0x0b5c473dL), tole(0x1c26a370L), tole(0x1de4c947L), tole(0x1fa2771eL), tole(0x1e601d29L), tole(0x1b2f0bacL), tole(0x1aed619bL), tole(0x18abdfc2L), tole(0x1969b5f5L), tole(0x1235f2c8L), tole(0x13f798ffL), tole(0x11b126a6L), tole(0x10734c91L), tole(0x153c5a14L), tole(0x14fe3023L), tole(0x16b88e7aL), tole(0x177ae44dL), tole(0x384d46e0L), tole(0x398f2cd7L), tole(0x3bc9928eL), tole(0x3a0bf8b9L), tole(0x3f44ee3cL), tole(0x3e86840bL), tole(0x3cc03a52L), tole(0x3d025065L), tole(0x365e1758L), tole(0x379c7d6fL), tole(0x35dac336L), tole(0x3418a901L), tole(0x3157bf84L), tole(0x3095d5b3L), tole(0x32d36beaL), tole(0x331101ddL), tole(0x246be590L), tole(0x25a98fa7L), tole(0x27ef31feL), tole(0x262d5bc9L), tole(0x23624d4cL), tole(0x22a0277bL), tole(0x20e69922L), tole(0x2124f315L), tole(0x2a78b428L), tole(0x2bbade1fL), tole(0x29fc6046L), tole(0x283e0a71L), tole(0x2d711cf4L), tole(0x2cb376c3L), tole(0x2ef5c89aL), tole(0x2f37a2adL), tole(0x709a8dc0L), tole(0x7158e7f7L), tole(0x731e59aeL), tole(0x72dc3399L), tole(0x7793251cL), tole(0x76514f2bL), tole(0x7417f172L), tole(0x75d59b45L), tole(0x7e89dc78L), tole(0x7f4bb64fL), tole(0x7d0d0816L), tole(0x7ccf6221L), tole(0x798074a4L), tole(0x78421e93L), tole(0x7a04a0caL), tole(0x7bc6cafdL), tole(0x6cbc2eb0L), tole(0x6d7e4487L), tole(0x6f38fadeL), tole(0x6efa90e9L), tole(0x6bb5866cL), tole(0x6a77ec5bL), tole(0x68315202L), tole(0x69f33835L), tole(0x62af7f08L), tole(0x636d153fL), tole(0x612bab66L), tole(0x60e9c151L), tole(0x65a6d7d4L), tole(0x6464bde3L), tole(0x662203baL), tole(0x67e0698dL), tole(0x48d7cb20L), tole(0x4915a117L), tole(0x4b531f4eL), tole(0x4a917579L), tole(0x4fde63fcL), tole(0x4e1c09cbL), tole(0x4c5ab792L), tole(0x4d98dda5L), tole(0x46c49a98L), tole(0x4706f0afL), tole(0x45404ef6L), tole(0x448224c1L), tole(0x41cd3244L), tole(0x400f5873L), tole(0x4249e62aL), tole(0x438b8c1dL), tole(0x54f16850L), tole(0x55330267L), tole(0x5775bc3eL), tole(0x56b7d609L), tole(0x53f8c08cL), tole(0x523aaabbL), tole(0x507c14e2L), tole(0x51be7ed5L), tole(0x5ae239e8L), tole(0x5b2053dfL), tole(0x5966ed86L), tole(0x58a487b1L), tole(0x5deb9134L), tole(0x5c29fb03L), tole(0x5e6f455aL), tole(0x5fad2f6dL), tole(0xe1351b80L), tole(0xe0f771b7L), tole(0xe2b1cfeeL), tole(0xe373a5d9L), tole(0xe63cb35cL), tole(0xe7fed96bL), tole(0xe5b86732L), tole(0xe47a0d05L), tole(0xef264a38L), tole(0xeee4200fL), tole(0xeca29e56L), tole(0xed60f461L), tole(0xe82fe2e4L), tole(0xe9ed88d3L), tole(0xebab368aL), tole(0xea695cbdL), tole(0xfd13b8f0L), tole(0xfcd1d2c7L), tole(0xfe976c9eL), tole(0xff5506a9L), tole(0xfa1a102cL), tole(0xfbd87a1bL), tole(0xf99ec442L), tole(0xf85cae75L), tole(0xf300e948L), tole(0xf2c2837fL), tole(0xf0843d26L), tole(0xf1465711L), tole(0xf4094194L), tole(0xf5cb2ba3L), tole(0xf78d95faL), tole(0xf64fffcdL), tole(0xd9785d60L), tole(0xd8ba3757L), tole(0xdafc890eL), tole(0xdb3ee339L), tole(0xde71f5bcL), tole(0xdfb39f8bL), tole(0xddf521d2L), tole(0xdc374be5L), tole(0xd76b0cd8L), tole(0xd6a966efL), tole(0xd4efd8b6L), tole(0xd52db281L), tole(0xd062a404L), tole(0xd1a0ce33L), tole(0xd3e6706aL), tole(0xd2241a5dL), tole(0xc55efe10L), tole(0xc49c9427L), tole(0xc6da2a7eL), tole(0xc7184049L), tole(0xc25756ccL), tole(0xc3953cfbL), tole(0xc1d382a2L), tole(0xc011e895L), tole(0xcb4dafa8L), tole(0xca8fc59fL), tole(0xc8c97bc6L), tole(0xc90b11f1L), tole(0xcc440774L), tole(0xcd866d43L), tole(0xcfc0d31aL), tole(0xce02b92dL), tole(0x91af9640L), tole(0x906dfc77L), tole(0x922b422eL), tole(0x93e92819L), tole(0x96a63e9cL), tole(0x976454abL), tole(0x9522eaf2L), tole(0x94e080c5L), tole(0x9fbcc7f8L), tole(0x9e7eadcfL), tole(0x9c381396L), tole(0x9dfa79a1L), tole(0x98b56f24L), tole(0x99770513L), tole(0x9b31bb4aL), tole(0x9af3d17dL), tole(0x8d893530L), tole(0x8c4b5f07L), tole(0x8e0de15eL), tole(0x8fcf8b69L), tole(0x8a809decL), tole(0x8b42f7dbL), tole(0x89044982L), tole(0x88c623b5L), tole(0x839a6488L), tole(0x82580ebfL), tole(0x801eb0e6L), tole(0x81dcdad1L), tole(0x8493cc54L), tole(0x8551a663L), tole(0x8717183aL), tole(0x86d5720dL), tole(0xa9e2d0a0L), tole(0xa820ba97L), tole(0xaa6604ceL), tole(0xaba46ef9L), tole(0xaeeb787cL), tole(0xaf29124bL), tole(0xad6fac12L), tole(0xacadc625L), tole(0xa7f18118L), tole(0xa633eb2fL), tole(0xa4755576L), tole(0xa5b73f41L), tole(0xa0f829c4L), tole(0xa13a43f3L), tole(0xa37cfdaaL), tole(0xa2be979dL), tole(0xb5c473d0L), tole(0xb40619e7L), tole(0xb640a7beL), tole(0xb782cd89L), tole(0xb2cddb0cL), tole(0xb30fb13bL), tole(0xb1490f62L), tole(0xb08b6555L), tole(0xbbd72268L), tole(0xba15485fL), tole(0xb853f606L), tole(0xb9919c31L), tole(0xbcde8ab4L), tole(0xbd1ce083L), tole(0xbf5a5edaL), tole(0xbe9834edL)}, { tole(0x00000000L), tole(0xb8bc6765L), tole(0xaa09c88bL), tole(0x12b5afeeL), tole(0x8f629757L), tole(0x37def032L), tole(0x256b5fdcL), tole(0x9dd738b9L), tole(0xc5b428efL), tole(0x7d084f8aL), tole(0x6fbde064L), tole(0xd7018701L), tole(0x4ad6bfb8L), tole(0xf26ad8ddL), tole(0xe0df7733L), tole(0x58631056L), tole(0x5019579fL), tole(0xe8a530faL), tole(0xfa109f14L), tole(0x42acf871L), tole(0xdf7bc0c8L), tole(0x67c7a7adL), tole(0x75720843L), tole(0xcdce6f26L), tole(0x95ad7f70L), tole(0x2d111815L), tole(0x3fa4b7fbL), tole(0x8718d09eL), tole(0x1acfe827L), tole(0xa2738f42L), tole(0xb0c620acL), tole(0x087a47c9L), tole(0xa032af3eL), tole(0x188ec85bL), tole(0x0a3b67b5L), tole(0xb28700d0L), tole(0x2f503869L), tole(0x97ec5f0cL), tole(0x8559f0e2L), tole(0x3de59787L), tole(0x658687d1L), tole(0xdd3ae0b4L), tole(0xcf8f4f5aL), tole(0x7733283fL), tole(0xeae41086L), tole(0x525877e3L), tole(0x40edd80dL), tole(0xf851bf68L), tole(0xf02bf8a1L), tole(0x48979fc4L), tole(0x5a22302aL), tole(0xe29e574fL), tole(0x7f496ff6L), tole(0xc7f50893L), tole(0xd540a77dL), tole(0x6dfcc018L), tole(0x359fd04eL), tole(0x8d23b72bL), tole(0x9f9618c5L), tole(0x272a7fa0L), tole(0xbafd4719L), tole(0x0241207cL), tole(0x10f48f92L), tole(0xa848e8f7L), tole(0x9b14583dL), tole(0x23a83f58L), tole(0x311d90b6L), tole(0x89a1f7d3L), tole(0x1476cf6aL), tole(0xaccaa80fL), tole(0xbe7f07e1L), tole(0x06c36084L), tole(0x5ea070d2L), tole(0xe61c17b7L), tole(0xf4a9b859L), tole(0x4c15df3cL), tole(0xd1c2e785L), tole(0x697e80e0L), tole(0x7bcb2f0eL), tole(0xc377486bL), tole(0xcb0d0fa2L), tole(0x73b168c7L), tole(0x6104c729L), tole(0xd9b8a04cL), tole(0x446f98f5L), tole(0xfcd3ff90L), tole(0xee66507eL), tole(0x56da371bL), tole(0x0eb9274dL), tole(0xb6054028L), tole(0xa4b0efc6L), tole(0x1c0c88a3L), tole(0x81dbb01aL), tole(0x3967d77fL), tole(0x2bd27891L), tole(0x936e1ff4L), tole(0x3b26f703L), tole(0x839a9066L), tole(0x912f3f88L), tole(0x299358edL), tole(0xb4446054L), tole(0x0cf80731L), tole(0x1e4da8dfL), tole(0xa6f1cfbaL), tole(0xfe92dfecL), tole(0x462eb889L), tole(0x549b1767L), tole(0xec277002L), tole(0x71f048bbL), tole(0xc94c2fdeL), tole(0xdbf98030L), tole(0x6345e755L), tole(0x6b3fa09cL), tole(0xd383c7f9L), tole(0xc1366817L), tole(0x798a0f72L), tole(0xe45d37cbL), tole(0x5ce150aeL), tole(0x4e54ff40L), tole(0xf6e89825L), tole(0xae8b8873L), tole(0x1637ef16L), tole(0x048240f8L), tole(0xbc3e279dL), tole(0x21e91f24L), tole(0x99557841L), tole(0x8be0d7afL), tole(0x335cb0caL), tole(0xed59b63bL), tole(0x55e5d15eL), tole(0x47507eb0L), tole(0xffec19d5L), tole(0x623b216cL), tole(0xda874609L), tole(0xc832e9e7L), tole(0x708e8e82L), tole(0x28ed9ed4L), tole(0x9051f9b1L), tole(0x82e4565fL), tole(0x3a58313aL), tole(0xa78f0983L), tole(0x1f336ee6L), tole(0x0d86c108L), tole(0xb53aa66dL), tole(0xbd40e1a4L), tole(0x05fc86c1L), tole(0x1749292fL), tole(0xaff54e4aL), tole(0x322276f3L), tole(0x8a9e1196L), tole(0x982bbe78L), tole(0x2097d91dL), tole(0x78f4c94bL), tole(0xc048ae2eL), tole(0xd2fd01c0L), tole(0x6a4166a5L), tole(0xf7965e1cL), tole(0x4f2a3979L), tole(0x5d9f9697L), tole(0xe523f1f2L), tole(0x4d6b1905L), tole(0xf5d77e60L), tole(0xe762d18eL), tole(0x5fdeb6ebL), tole(0xc2098e52L), tole(0x7ab5e937L), tole(0x680046d9L), tole(0xd0bc21bcL), tole(0x88df31eaL), tole(0x3063568fL), tole(0x22d6f961L), tole(0x9a6a9e04L), tole(0x07bda6bdL), tole(0xbf01c1d8L), tole(0xadb46e36L), tole(0x15080953L), tole(0x1d724e9aL), tole(0xa5ce29ffL), tole(0xb77b8611L), tole(0x0fc7e174L), tole(0x9210d9cdL), tole(0x2aacbea8L), tole(0x38191146L), tole(0x80a57623L), tole(0xd8c66675L), tole(0x607a0110L), tole(0x72cfaefeL), tole(0xca73c99bL), tole(0x57a4f122L), tole(0xef189647L), tole(0xfdad39a9L), tole(0x45115eccL), tole(0x764dee06L), tole(0xcef18963L), tole(0xdc44268dL), tole(0x64f841e8L), tole(0xf92f7951L), tole(0x41931e34L), tole(0x5326b1daL), tole(0xeb9ad6bfL), tole(0xb3f9c6e9L), tole(0x0b45a18cL), tole(0x19f00e62L), tole(0xa14c6907L), tole(0x3c9b51beL), tole(0x842736dbL), tole(0x96929935L), tole(0x2e2efe50L), tole(0x2654b999L), tole(0x9ee8defcL), tole(0x8c5d7112L), tole(0x34e11677L), tole(0xa9362eceL), tole(0x118a49abL), tole(0x033fe645L), tole(0xbb838120L), tole(0xe3e09176L), tole(0x5b5cf613L), tole(0x49e959fdL), tole(0xf1553e98L), tole(0x6c820621L), tole(0xd43e6144L), tole(0xc68bceaaL), tole(0x7e37a9cfL), tole(0xd67f4138L), tole(0x6ec3265dL), tole(0x7c7689b3L), tole(0xc4caeed6L), tole(0x591dd66fL), tole(0xe1a1b10aL), tole(0xf3141ee4L), tole(0x4ba87981L), tole(0x13cb69d7L), tole(0xab770eb2L), tole(0xb9c2a15cL), tole(0x017ec639L), tole(0x9ca9fe80L), tole(0x241599e5L), tole(0x36a0360bL), tole(0x8e1c516eL), tole(0x866616a7L), tole(0x3eda71c2L), tole(0x2c6fde2cL), tole(0x94d3b949L), tole(0x090481f0L), tole(0xb1b8e695L), tole(0xa30d497bL), tole(0x1bb12e1eL), tole(0x43d23e48L), tole(0xfb6e592dL), tole(0xe9dbf6c3L), tole(0x516791a6L), tole(0xccb0a91fL), tole(0x740cce7aL), tole(0x66b96194L), tole(0xde0506f1L)}, }; static u32 crc32ctable_le[4][256] = {{ tole(0x00000000L), tole(0xf26b8303L), tole(0xe13b70f7L), tole(0x1350f3f4L), tole(0xc79a971fL), tole(0x35f1141cL), tole(0x26a1e7e8L), tole(0xd4ca64ebL), tole(0x8ad958cfL), tole(0x78b2dbccL), tole(0x6be22838L), tole(0x9989ab3bL), tole(0x4d43cfd0L), tole(0xbf284cd3L), tole(0xac78bf27L), tole(0x5e133c24L), tole(0x105ec76fL), tole(0xe235446cL), tole(0xf165b798L), tole(0x030e349bL), tole(0xd7c45070L), tole(0x25afd373L), tole(0x36ff2087L), tole(0xc494a384L), tole(0x9a879fa0L), tole(0x68ec1ca3L), tole(0x7bbcef57L), tole(0x89d76c54L), tole(0x5d1d08bfL), tole(0xaf768bbcL), tole(0xbc267848L), tole(0x4e4dfb4bL), tole(0x20bd8edeL), tole(0xd2d60dddL), tole(0xc186fe29L), tole(0x33ed7d2aL), tole(0xe72719c1L), tole(0x154c9ac2L), tole(0x061c6936L), tole(0xf477ea35L), tole(0xaa64d611L), tole(0x580f5512L), tole(0x4b5fa6e6L), tole(0xb93425e5L), tole(0x6dfe410eL), tole(0x9f95c20dL), tole(0x8cc531f9L), tole(0x7eaeb2faL), tole(0x30e349b1L), tole(0xc288cab2L), tole(0xd1d83946L), tole(0x23b3ba45L), tole(0xf779deaeL), tole(0x05125dadL), tole(0x1642ae59L), tole(0xe4292d5aL), tole(0xba3a117eL), tole(0x4851927dL), tole(0x5b016189L), tole(0xa96ae28aL), tole(0x7da08661L), tole(0x8fcb0562L), tole(0x9c9bf696L), tole(0x6ef07595L), tole(0x417b1dbcL), tole(0xb3109ebfL), tole(0xa0406d4bL), tole(0x522bee48L), tole(0x86e18aa3L), tole(0x748a09a0L), tole(0x67dafa54L), tole(0x95b17957L), tole(0xcba24573L), tole(0x39c9c670L), tole(0x2a993584L), tole(0xd8f2b687L), tole(0x0c38d26cL), tole(0xfe53516fL), tole(0xed03a29bL), tole(0x1f682198L), tole(0x5125dad3L), tole(0xa34e59d0L), tole(0xb01eaa24L), tole(0x42752927L), tole(0x96bf4dccL), tole(0x64d4cecfL), tole(0x77843d3bL), tole(0x85efbe38L), tole(0xdbfc821cL), tole(0x2997011fL), tole(0x3ac7f2ebL), tole(0xc8ac71e8L), tole(0x1c661503L), tole(0xee0d9600L), tole(0xfd5d65f4L), tole(0x0f36e6f7L), tole(0x61c69362L), tole(0x93ad1061L), tole(0x80fde395L), tole(0x72966096L), tole(0xa65c047dL), tole(0x5437877eL), tole(0x4767748aL), tole(0xb50cf789L), tole(0xeb1fcbadL), tole(0x197448aeL), tole(0x0a24bb5aL), tole(0xf84f3859L), tole(0x2c855cb2L), tole(0xdeeedfb1L), tole(0xcdbe2c45L), tole(0x3fd5af46L), tole(0x7198540dL), tole(0x83f3d70eL), tole(0x90a324faL), tole(0x62c8a7f9L), tole(0xb602c312L), tole(0x44694011L), tole(0x5739b3e5L), tole(0xa55230e6L), tole(0xfb410cc2L), tole(0x092a8fc1L), tole(0x1a7a7c35L), tole(0xe811ff36L), tole(0x3cdb9bddL), tole(0xceb018deL), tole(0xdde0eb2aL), tole(0x2f8b6829L), tole(0x82f63b78L), tole(0x709db87bL), tole(0x63cd4b8fL), tole(0x91a6c88cL), tole(0x456cac67L), tole(0xb7072f64L), tole(0xa457dc90L), tole(0x563c5f93L), tole(0x082f63b7L), tole(0xfa44e0b4L), tole(0xe9141340L), tole(0x1b7f9043L), tole(0xcfb5f4a8L), tole(0x3dde77abL), tole(0x2e8e845fL), tole(0xdce5075cL), tole(0x92a8fc17L), tole(0x60c37f14L), tole(0x73938ce0L), tole(0x81f80fe3L), tole(0x55326b08L), tole(0xa759e80bL), tole(0xb4091bffL), tole(0x466298fcL), tole(0x1871a4d8L), tole(0xea1a27dbL), tole(0xf94ad42fL), tole(0x0b21572cL), tole(0xdfeb33c7L), tole(0x2d80b0c4L), tole(0x3ed04330L), tole(0xccbbc033L), tole(0xa24bb5a6L), tole(0x502036a5L), tole(0x4370c551L), tole(0xb11b4652L), tole(0x65d122b9L), tole(0x97baa1baL), tole(0x84ea524eL), tole(0x7681d14dL), tole(0x2892ed69L), tole(0xdaf96e6aL), tole(0xc9a99d9eL), tole(0x3bc21e9dL), tole(0xef087a76L), tole(0x1d63f975L), tole(0x0e330a81L), tole(0xfc588982L), tole(0xb21572c9L), tole(0x407ef1caL), tole(0x532e023eL), tole(0xa145813dL), tole(0x758fe5d6L), tole(0x87e466d5L), tole(0x94b49521L), tole(0x66df1622L), tole(0x38cc2a06L), tole(0xcaa7a905L), tole(0xd9f75af1L), tole(0x2b9cd9f2L), tole(0xff56bd19L), tole(0x0d3d3e1aL), tole(0x1e6dcdeeL), tole(0xec064eedL), tole(0xc38d26c4L), tole(0x31e6a5c7L), tole(0x22b65633L), tole(0xd0ddd530L), tole(0x0417b1dbL), tole(0xf67c32d8L), tole(0xe52cc12cL), tole(0x1747422fL), tole(0x49547e0bL), tole(0xbb3ffd08L), tole(0xa86f0efcL), tole(0x5a048dffL), tole(0x8ecee914L), tole(0x7ca56a17L), tole(0x6ff599e3L), tole(0x9d9e1ae0L), tole(0xd3d3e1abL), tole(0x21b862a8L), tole(0x32e8915cL), tole(0xc083125fL), tole(0x144976b4L), tole(0xe622f5b7L), tole(0xf5720643L), tole(0x07198540L), tole(0x590ab964L), tole(0xab613a67L), tole(0xb831c993L), tole(0x4a5a4a90L), tole(0x9e902e7bL), tole(0x6cfbad78L), tole(0x7fab5e8cL), tole(0x8dc0dd8fL), tole(0xe330a81aL), tole(0x115b2b19L), tole(0x020bd8edL), tole(0xf0605beeL), tole(0x24aa3f05L), tole(0xd6c1bc06L), tole(0xc5914ff2L), tole(0x37faccf1L), tole(0x69e9f0d5L), tole(0x9b8273d6L), tole(0x88d28022L), tole(0x7ab90321L), tole(0xae7367caL), tole(0x5c18e4c9L), tole(0x4f48173dL), tole(0xbd23943eL), tole(0xf36e6f75L), tole(0x0105ec76L), tole(0x12551f82L), tole(0xe03e9c81L), tole(0x34f4f86aL), tole(0xc69f7b69L), tole(0xd5cf889dL), tole(0x27a40b9eL), tole(0x79b737baL), tole(0x8bdcb4b9L), tole(0x988c474dL), tole(0x6ae7c44eL), tole(0xbe2da0a5L), tole(0x4c4623a6L), tole(0x5f16d052L), tole(0xad7d5351L)}, { tole(0x00000000L), tole(0x13a29877L), tole(0x274530eeL), tole(0x34e7a899L), tole(0x4e8a61dcL), tole(0x5d28f9abL), tole(0x69cf5132L), tole(0x7a6dc945L), tole(0x9d14c3b8L), tole(0x8eb65bcfL), tole(0xba51f356L), tole(0xa9f36b21L), tole(0xd39ea264L), tole(0xc03c3a13L), tole(0xf4db928aL), tole(0xe7790afdL), tole(0x3fc5f181L), tole(0x2c6769f6L), tole(0x1880c16fL), tole(0x0b225918L), tole(0x714f905dL), tole(0x62ed082aL), tole(0x560aa0b3L), tole(0x45a838c4L), tole(0xa2d13239L), tole(0xb173aa4eL), tole(0x859402d7L), tole(0x96369aa0L), tole(0xec5b53e5L), tole(0xfff9cb92L), tole(0xcb1e630bL), tole(0xd8bcfb7cL), tole(0x7f8be302L), tole(0x6c297b75L), tole(0x58ced3ecL), tole(0x4b6c4b9bL), tole(0x310182deL), tole(0x22a31aa9L), tole(0x1644b230L), tole(0x05e62a47L), tole(0xe29f20baL), tole(0xf13db8cdL), tole(0xc5da1054L), tole(0xd6788823L), tole(0xac154166L), tole(0xbfb7d911L), tole(0x8b507188L), tole(0x98f2e9ffL), tole(0x404e1283L), tole(0x53ec8af4L), tole(0x670b226dL), tole(0x74a9ba1aL), tole(0x0ec4735fL), tole(0x1d66eb28L), tole(0x298143b1L), tole(0x3a23dbc6L), tole(0xdd5ad13bL), tole(0xcef8494cL), tole(0xfa1fe1d5L), tole(0xe9bd79a2L), tole(0x93d0b0e7L), tole(0x80722890L), tole(0xb4958009L), tole(0xa737187eL), tole(0xff17c604L), tole(0xecb55e73L), tole(0xd852f6eaL), tole(0xcbf06e9dL), tole(0xb19da7d8L), tole(0xa23f3fafL), tole(0x96d89736L), tole(0x857a0f41L), tole(0x620305bcL), tole(0x71a19dcbL), tole(0x45463552L), tole(0x56e4ad25L), tole(0x2c896460L), tole(0x3f2bfc17L), tole(0x0bcc548eL), tole(0x186eccf9L), tole(0xc0d23785L), tole(0xd370aff2L), tole(0xe797076bL), tole(0xf4359f1cL), tole(0x8e585659L), tole(0x9dface2eL), tole(0xa91d66b7L), tole(0xbabffec0L), tole(0x5dc6f43dL), tole(0x4e646c4aL), tole(0x7a83c4d3L), tole(0x69215ca4L), tole(0x134c95e1L), tole(0x00ee0d96L), tole(0x3409a50fL), tole(0x27ab3d78L), tole(0x809c2506L), tole(0x933ebd71L), tole(0xa7d915e8L), tole(0xb47b8d9fL), tole(0xce1644daL), tole(0xddb4dcadL), tole(0xe9537434L), tole(0xfaf1ec43L), tole(0x1d88e6beL), tole(0x0e2a7ec9L), tole(0x3acdd650L), tole(0x296f4e27L), tole(0x53028762L), tole(0x40a01f15L), tole(0x7447b78cL), tole(0x67e52ffbL), tole(0xbf59d487L), tole(0xacfb4cf0L), tole(0x981ce469L), tole(0x8bbe7c1eL), tole(0xf1d3b55bL), tole(0xe2712d2cL), tole(0xd69685b5L), tole(0xc5341dc2L), tole(0x224d173fL), tole(0x31ef8f48L), tole(0x050827d1L), tole(0x16aabfa6L), tole(0x6cc776e3L), tole(0x7f65ee94L), tole(0x4b82460dL), tole(0x5820de7aL), tole(0xfbc3faf9L), tole(0xe861628eL), tole(0xdc86ca17L), tole(0xcf245260L), tole(0xb5499b25L), tole(0xa6eb0352L), tole(0x920cabcbL), tole(0x81ae33bcL), tole(0x66d73941L), tole(0x7575a136L), tole(0x419209afL), tole(0x523091d8L), tole(0x285d589dL), tole(0x3bffc0eaL), tole(0x0f186873L), tole(0x1cbaf004L), tole(0xc4060b78L), tole(0xd7a4930fL), tole(0xe3433b96L), tole(0xf0e1a3e1L), tole(0x8a8c6aa4L), tole(0x992ef2d3L), tole(0xadc95a4aL), tole(0xbe6bc23dL), tole(0x5912c8c0L), tole(0x4ab050b7L), tole(0x7e57f82eL), tole(0x6df56059L), tole(0x1798a91cL), tole(0x043a316bL), tole(0x30dd99f2L), tole(0x237f0185L), tole(0x844819fbL), tole(0x97ea818cL), tole(0xa30d2915L), tole(0xb0afb162L), tole(0xcac27827L), tole(0xd960e050L), tole(0xed8748c9L), tole(0xfe25d0beL), tole(0x195cda43L), tole(0x0afe4234L), tole(0x3e19eaadL), tole(0x2dbb72daL), tole(0x57d6bb9fL), tole(0x447423e8L), tole(0x70938b71L), tole(0x63311306L), tole(0xbb8de87aL), tole(0xa82f700dL), tole(0x9cc8d894L), tole(0x8f6a40e3L), tole(0xf50789a6L), tole(0xe6a511d1L), tole(0xd242b948L), tole(0xc1e0213fL), tole(0x26992bc2L), tole(0x353bb3b5L), tole(0x01dc1b2cL), tole(0x127e835bL), tole(0x68134a1eL), tole(0x7bb1d269L), tole(0x4f567af0L), tole(0x5cf4e287L), tole(0x04d43cfdL), tole(0x1776a48aL), tole(0x23910c13L), tole(0x30339464L), tole(0x4a5e5d21L), tole(0x59fcc556L), tole(0x6d1b6dcfL), tole(0x7eb9f5b8L), tole(0x99c0ff45L), tole(0x8a626732L), tole(0xbe85cfabL), tole(0xad2757dcL), tole(0xd74a9e99L), tole(0xc4e806eeL), tole(0xf00fae77L), tole(0xe3ad3600L), tole(0x3b11cd7cL), tole(0x28b3550bL), tole(0x1c54fd92L), tole(0x0ff665e5L), tole(0x759baca0L), tole(0x663934d7L), tole(0x52de9c4eL), tole(0x417c0439L), tole(0xa6050ec4L), tole(0xb5a796b3L), tole(0x81403e2aL), tole(0x92e2a65dL), tole(0xe88f6f18L), tole(0xfb2df76fL), tole(0xcfca5ff6L), tole(0xdc68c781L), tole(0x7b5fdfffL), tole(0x68fd4788L), tole(0x5c1aef11L), tole(0x4fb87766L), tole(0x35d5be23L), tole(0x26772654L), tole(0x12908ecdL), tole(0x013216baL), tole(0xe64b1c47L), tole(0xf5e98430L), tole(0xc10e2ca9L), tole(0xd2acb4deL), tole(0xa8c17d9bL), tole(0xbb63e5ecL), tole(0x8f844d75L), tole(0x9c26d502L), tole(0x449a2e7eL), tole(0x5738b609L), tole(0x63df1e90L), tole(0x707d86e7L), tole(0x0a104fa2L), tole(0x19b2d7d5L), tole(0x2d557f4cL), tole(0x3ef7e73bL), tole(0xd98eedc6L), tole(0xca2c75b1L), tole(0xfecbdd28L), tole(0xed69455fL), tole(0x97048c1aL), tole(0x84a6146dL), tole(0xb041bcf4L), tole(0xa3e32483L)}, { tole(0x00000000L), tole(0xa541927eL), tole(0x4f6f520dL), tole(0xea2ec073L), tole(0x9edea41aL), tole(0x3b9f3664L), tole(0xd1b1f617L), tole(0x74f06469L), tole(0x38513ec5L), tole(0x9d10acbbL), tole(0x773e6cc8L), tole(0xd27ffeb6L), tole(0xa68f9adfL), tole(0x03ce08a1L), tole(0xe9e0c8d2L), tole(0x4ca15aacL), tole(0x70a27d8aL), tole(0xd5e3eff4L), tole(0x3fcd2f87L), tole(0x9a8cbdf9L), tole(0xee7cd990L), tole(0x4b3d4beeL), tole(0xa1138b9dL), tole(0x045219e3L), tole(0x48f3434fL), tole(0xedb2d131L), tole(0x079c1142L), tole(0xa2dd833cL), tole(0xd62de755L), tole(0x736c752bL), tole(0x9942b558L), tole(0x3c032726L), tole(0xe144fb14L), tole(0x4405696aL), tole(0xae2ba919L), tole(0x0b6a3b67L), tole(0x7f9a5f0eL), tole(0xdadbcd70L), tole(0x30f50d03L), tole(0x95b49f7dL), tole(0xd915c5d1L), tole(0x7c5457afL), tole(0x967a97dcL), tole(0x333b05a2L), tole(0x47cb61cbL), tole(0xe28af3b5L), tole(0x08a433c6L), tole(0xade5a1b8L), tole(0x91e6869eL), tole(0x34a714e0L), tole(0xde89d493L), tole(0x7bc846edL), tole(0x0f382284L), tole(0xaa79b0faL), tole(0x40577089L), tole(0xe516e2f7L), tole(0xa9b7b85bL), tole(0x0cf62a25L), tole(0xe6d8ea56L), tole(0x43997828L), tole(0x37691c41L), tole(0x92288e3fL), tole(0x78064e4cL), tole(0xdd47dc32L), tole(0xc76580d9L), tole(0x622412a7L), tole(0x880ad2d4L), tole(0x2d4b40aaL), tole(0x59bb24c3L), tole(0xfcfab6bdL), tole(0x16d476ceL), tole(0xb395e4b0L), tole(0xff34be1cL), tole(0x5a752c62L), tole(0xb05bec11L), tole(0x151a7e6fL), tole(0x61ea1a06L), tole(0xc4ab8878L), tole(0x2e85480bL), tole(0x8bc4da75L), tole(0xb7c7fd53L), tole(0x12866f2dL), tole(0xf8a8af5eL), tole(0x5de93d20L), tole(0x29195949L), tole(0x8c58cb37L), tole(0x66760b44L), tole(0xc337993aL), tole(0x8f96c396L), tole(0x2ad751e8L), tole(0xc0f9919bL), tole(0x65b803e5L), tole(0x1148678cL), tole(0xb409f5f2L), tole(0x5e273581L), tole(0xfb66a7ffL), tole(0x26217bcdL), tole(0x8360e9b3L), tole(0x694e29c0L), tole(0xcc0fbbbeL), tole(0xb8ffdfd7L), tole(0x1dbe4da9L), tole(0xf7908ddaL), tole(0x52d11fa4L), tole(0x1e704508L), tole(0xbb31d776L), tole(0x511f1705L), tole(0xf45e857bL), tole(0x80aee112L), tole(0x25ef736cL), tole(0xcfc1b31fL), tole(0x6a802161L), tole(0x56830647L), tole(0xf3c29439L), tole(0x19ec544aL), tole(0xbcadc634L), tole(0xc85da25dL), tole(0x6d1c3023L), tole(0x8732f050L), tole(0x2273622eL), tole(0x6ed23882L), tole(0xcb93aafcL), tole(0x21bd6a8fL), tole(0x84fcf8f1L), tole(0xf00c9c98L), tole(0x554d0ee6L), tole(0xbf63ce95L), tole(0x1a225cebL), tole(0x8b277743L), tole(0x2e66e53dL), tole(0xc448254eL), tole(0x6109b730L), tole(0x15f9d359L), tole(0xb0b84127L), tole(0x5a968154L), tole(0xffd7132aL), tole(0xb3764986L), tole(0x1637dbf8L), tole(0xfc191b8bL), tole(0x595889f5L), tole(0x2da8ed9cL), tole(0x88e97fe2L), tole(0x62c7bf91L), tole(0xc7862defL), tole(0xfb850ac9L), tole(0x5ec498b7L), tole(0xb4ea58c4L), tole(0x11abcabaL), tole(0x655baed3L), tole(0xc01a3cadL), tole(0x2a34fcdeL), tole(0x8f756ea0L), tole(0xc3d4340cL), tole(0x6695a672L), tole(0x8cbb6601L), tole(0x29faf47fL), tole(0x5d0a9016L), tole(0xf84b0268L), tole(0x1265c21bL), tole(0xb7245065L), tole(0x6a638c57L), tole(0xcf221e29L), tole(0x250cde5aL), tole(0x804d4c24L), tole(0xf4bd284dL), tole(0x51fcba33L), tole(0xbbd27a40L), tole(0x1e93e83eL), tole(0x5232b292L), tole(0xf77320ecL), tole(0x1d5de09fL), tole(0xb81c72e1L), tole(0xccec1688L), tole(0x69ad84f6L), tole(0x83834485L), tole(0x26c2d6fbL), tole(0x1ac1f1ddL), tole(0xbf8063a3L), tole(0x55aea3d0L), tole(0xf0ef31aeL), tole(0x841f55c7L), tole(0x215ec7b9L), tole(0xcb7007caL), tole(0x6e3195b4L), tole(0x2290cf18L), tole(0x87d15d66L), tole(0x6dff9d15L), tole(0xc8be0f6bL), tole(0xbc4e6b02L), tole(0x190ff97cL), tole(0xf321390fL), tole(0x5660ab71L), tole(0x4c42f79aL), tole(0xe90365e4L), tole(0x032da597L), tole(0xa66c37e9L), tole(0xd29c5380L), tole(0x77ddc1feL), tole(0x9df3018dL), tole(0x38b293f3L), tole(0x7413c95fL), tole(0xd1525b21L), tole(0x3b7c9b52L), tole(0x9e3d092cL), tole(0xeacd6d45L), tole(0x4f8cff3bL), tole(0xa5a23f48L), tole(0x00e3ad36L), tole(0x3ce08a10L), tole(0x99a1186eL), tole(0x738fd81dL), tole(0xd6ce4a63L), tole(0xa23e2e0aL), tole(0x077fbc74L), tole(0xed517c07L), tole(0x4810ee79L), tole(0x04b1b4d5L), tole(0xa1f026abL), tole(0x4bdee6d8L), tole(0xee9f74a6L), tole(0x9a6f10cfL), tole(0x3f2e82b1L), tole(0xd50042c2L), tole(0x7041d0bcL), tole(0xad060c8eL), tole(0x08479ef0L), tole(0xe2695e83L), tole(0x4728ccfdL), tole(0x33d8a894L), tole(0x96993aeaL), tole(0x7cb7fa99L), tole(0xd9f668e7L), tole(0x9557324bL), tole(0x3016a035L), tole(0xda386046L), tole(0x7f79f238L), tole(0x0b899651L), tole(0xaec8042fL), tole(0x44e6c45cL), tole(0xe1a75622L), tole(0xdda47104L), tole(0x78e5e37aL), tole(0x92cb2309L), tole(0x378ab177L), tole(0x437ad51eL), tole(0xe63b4760L), tole(0x0c158713L), tole(0xa954156dL), tole(0xe5f54fc1L), tole(0x40b4ddbfL), tole(0xaa9a1dccL), tole(0x0fdb8fb2L), tole(0x7b2bebdbL), tole(0xde6a79a5L), tole(0x3444b9d6L), tole(0x91052ba8L)}, { tole(0x00000000L), tole(0xdd45aab8L), tole(0xbf672381L), tole(0x62228939L), tole(0x7b2231f3L), tole(0xa6679b4bL), tole(0xc4451272L), tole(0x1900b8caL), tole(0xf64463e6L), tole(0x2b01c95eL), tole(0x49234067L), tole(0x9466eadfL), tole(0x8d665215L), tole(0x5023f8adL), tole(0x32017194L), tole(0xef44db2cL), tole(0xe964b13dL), tole(0x34211b85L), tole(0x560392bcL), tole(0x8b463804L), tole(0x924680ceL), tole(0x4f032a76L), tole(0x2d21a34fL), tole(0xf06409f7L), tole(0x1f20d2dbL), tole(0xc2657863L), tole(0xa047f15aL), tole(0x7d025be2L), tole(0x6402e328L), tole(0xb9474990L), tole(0xdb65c0a9L), tole(0x06206a11L), tole(0xd725148bL), tole(0x0a60be33L), tole(0x6842370aL), tole(0xb5079db2L), tole(0xac072578L), tole(0x71428fc0L), tole(0x136006f9L), tole(0xce25ac41L), tole(0x2161776dL), tole(0xfc24ddd5L), tole(0x9e0654ecL), tole(0x4343fe54L), tole(0x5a43469eL), tole(0x8706ec26L), tole(0xe524651fL), tole(0x3861cfa7L), tole(0x3e41a5b6L), tole(0xe3040f0eL), tole(0x81268637L), tole(0x5c632c8fL), tole(0x45639445L), tole(0x98263efdL), tole(0xfa04b7c4L), tole(0x27411d7cL), tole(0xc805c650L), tole(0x15406ce8L), tole(0x7762e5d1L), tole(0xaa274f69L), tole(0xb327f7a3L), tole(0x6e625d1bL), tole(0x0c40d422L), tole(0xd1057e9aL), tole(0xaba65fe7L), tole(0x76e3f55fL), tole(0x14c17c66L), tole(0xc984d6deL), tole(0xd0846e14L), tole(0x0dc1c4acL), tole(0x6fe34d95L), tole(0xb2a6e72dL), tole(0x5de23c01L), tole(0x80a796b9L), tole(0xe2851f80L), tole(0x3fc0b538L), tole(0x26c00df2L), tole(0xfb85a74aL), tole(0x99a72e73L), tole(0x44e284cbL), tole(0x42c2eedaL), tole(0x9f874462L), tole(0xfda5cd5bL), tole(0x20e067e3L), tole(0x39e0df29L), tole(0xe4a57591L), tole(0x8687fca8L), tole(0x5bc25610L), tole(0xb4868d3cL), tole(0x69c32784L), tole(0x0be1aebdL), tole(0xd6a40405L), tole(0xcfa4bccfL), tole(0x12e11677L), tole(0x70c39f4eL), tole(0xad8635f6L), tole(0x7c834b6cL), tole(0xa1c6e1d4L), tole(0xc3e468edL), tole(0x1ea1c255L), tole(0x07a17a9fL), tole(0xdae4d027L), tole(0xb8c6591eL), tole(0x6583f3a6L), tole(0x8ac7288aL), tole(0x57828232L), tole(0x35a00b0bL), tole(0xe8e5a1b3L), tole(0xf1e51979L), tole(0x2ca0b3c1L), tole(0x4e823af8L), tole(0x93c79040L), tole(0x95e7fa51L), tole(0x48a250e9L), tole(0x2a80d9d0L), tole(0xf7c57368L), tole(0xeec5cba2L), tole(0x3380611aL), tole(0x51a2e823L), tole(0x8ce7429bL), tole(0x63a399b7L), tole(0xbee6330fL), tole(0xdcc4ba36L), tole(0x0181108eL), tole(0x1881a844L), tole(0xc5c402fcL), tole(0xa7e68bc5L), tole(0x7aa3217dL), tole(0x52a0c93fL), tole(0x8fe56387L), tole(0xedc7eabeL), tole(0x30824006L), tole(0x2982f8ccL), tole(0xf4c75274L), tole(0x96e5db4dL), tole(0x4ba071f5L), tole(0xa4e4aad9L), tole(0x79a10061L), tole(0x1b838958L), tole(0xc6c623e0L), tole(0xdfc69b2aL), tole(0x02833192L), tole(0x60a1b8abL), tole(0xbde41213L), tole(0xbbc47802L), tole(0x6681d2baL), tole(0x04a35b83L), tole(0xd9e6f13bL), tole(0xc0e649f1L), tole(0x1da3e349L), tole(0x7f816a70L), tole(0xa2c4c0c8L), tole(0x4d801be4L), tole(0x90c5b15cL), tole(0xf2e73865L), tole(0x2fa292ddL), tole(0x36a22a17L), tole(0xebe780afL), tole(0x89c50996L), tole(0x5480a32eL), tole(0x8585ddb4L), tole(0x58c0770cL), tole(0x3ae2fe35L), tole(0xe7a7548dL), tole(0xfea7ec47L), tole(0x23e246ffL), tole(0x41c0cfc6L), tole(0x9c85657eL), tole(0x73c1be52L), tole(0xae8414eaL), tole(0xcca69dd3L), tole(0x11e3376bL), tole(0x08e38fa1L), tole(0xd5a62519L), tole(0xb784ac20L), tole(0x6ac10698L), tole(0x6ce16c89L), tole(0xb1a4c631L), tole(0xd3864f08L), tole(0x0ec3e5b0L), tole(0x17c35d7aL), tole(0xca86f7c2L), tole(0xa8a47efbL), tole(0x75e1d443L), tole(0x9aa50f6fL), tole(0x47e0a5d7L), tole(0x25c22ceeL), tole(0xf8878656L), tole(0xe1873e9cL), tole(0x3cc29424L), tole(0x5ee01d1dL), tole(0x83a5b7a5L), tole(0xf90696d8L), tole(0x24433c60L), tole(0x4661b559L), tole(0x9b241fe1L), tole(0x8224a72bL), tole(0x5f610d93L), tole(0x3d4384aaL), tole(0xe0062e12L), tole(0x0f42f53eL), tole(0xd2075f86L), tole(0xb025d6bfL), tole(0x6d607c07L), tole(0x7460c4cdL), tole(0xa9256e75L), tole(0xcb07e74cL), tole(0x16424df4L), tole(0x106227e5L), tole(0xcd278d5dL), tole(0xaf050464L), tole(0x7240aedcL), tole(0x6b401616L), tole(0xb605bcaeL), tole(0xd4273597L), tole(0x09629f2fL), tole(0xe6264403L), tole(0x3b63eebbL), tole(0x59416782L), tole(0x8404cd3aL), tole(0x9d0475f0L), tole(0x4041df48L), tole(0x22635671L), tole(0xff26fcc9L), tole(0x2e238253L), tole(0xf36628ebL), tole(0x9144a1d2L), tole(0x4c010b6aL), tole(0x5501b3a0L), tole(0x88441918L), tole(0xea669021L), tole(0x37233a99L), tole(0xd867e1b5L), tole(0x05224b0dL), tole(0x6700c234L), tole(0xba45688cL), tole(0xa345d046L), tole(0x7e007afeL), tole(0x1c22f3c7L), tole(0xc167597fL), tole(0xc747336eL), tole(0x1a0299d6L), tole(0x782010efL), tole(0xa565ba57L), tole(0xbc65029dL), tole(0x6120a825L), tole(0x0302211cL), tole(0xde478ba4L), tole(0x31035088L), tole(0xec46fa30L), tole(0x8e647309L), tole(0x5321d9b1L), tole(0x4a21617bL), tole(0x9764cbc3L), tole(0xf54642faL), tole(0x2803e842L)}, }; partclone-0.2.86/src/xfs/handle.h000066400000000000000000000042261262102574200165760ustar00rootroot00000000000000/* * Copyright (c) 1995, 2001-2003, 2005 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __HANDLE_H__ #define __HANDLE_H__ #ifdef __cplusplus extern "C" { #endif struct fsdmidata; struct attrlist_cursor; struct parent; extern int path_to_handle (char *__path, void **__hanp, size_t *__hlen); extern int path_to_fshandle (char *__path, void **__fshanp, size_t *__fshlen); extern int fd_to_handle (int fd, void **hanp, size_t *hlen); extern int handle_to_fshandle (void *__hanp, size_t __hlen, void **__fshanp, size_t *__fshlen); extern void free_handle (void *__hanp, size_t __hlen); extern int open_by_fshandle (void *__fshanp, size_t __fshlen, int __rw); extern int open_by_handle (void *__hanp, size_t __hlen, int __rw); extern int readlink_by_handle (void *__hanp, size_t __hlen, void *__buf, size_t __bs); extern int attr_multi_by_handle (void *__hanp, size_t __hlen, void *__buf, int __rtrvcnt, int __flags); extern int attr_list_by_handle (void *__hanp, size_t __hlen, void *__buf, size_t __bufsize, int __flags, struct attrlist_cursor *__cursor); extern int parents_by_handle(void *__hanp, size_t __hlen, struct parent *__buf, size_t __bufsize, unsigned int *__count); extern int parentpaths_by_handle(void *__hanp, size_t __hlen, struct parent *__buf, size_t __bufsize, unsigned int *__count); extern int fssetdm_by_handle (void *__hanp, size_t __hlen, struct fsdmidata *__fsdmi); #ifdef __cplusplus } #endif #endif /* __HANDLE_H__ */ partclone-0.2.86/src/xfs/hlist.h000066400000000000000000000040231262102574200164610ustar00rootroot00000000000000/* * double-linked hash list with single head implementation taken from linux * kernel headers as of 2.6.38-rc1. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __HLIST_H__ #define __HLIST_H__ struct hlist_node { struct hlist_node *next; struct hlist_node **pprev; }; struct hlist_head { struct hlist_node *first; }; #define HLIST_HEAD_INIT { .first = NULL } static inline void INIT_HLIST_NODE(struct hlist_node *h) { h->next = NULL; h->pprev = NULL; } static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) { struct hlist_node *first = h->first; n->next = first; if (first) first->pprev = &n->next; h->first = n; n->pprev = &h->first; } static inline void __hlist_del(struct hlist_node *n) { struct hlist_node *next = n->next; struct hlist_node **pprev = n->pprev; *pprev = next; if (next) next->pprev = pprev; } static inline void hlist_del(struct hlist_node *n) { __hlist_del(n); } #define hlist_entry(ptr, type, member) ({ \ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ (type *)( (char *)__mptr - offsetof(type,member) );}) #define hlist_for_each(pos, head) \ for (pos = (head)->first; pos; pos = pos->next) #define hlist_for_each_entry(tpos, pos, head, member) \ for (pos = (head)->first; \ pos && ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ pos = pos->next) #endif /* __LIST_H__ */ partclone-0.2.86/src/xfs/init.c000066400000000000000000000521531262102574200163030ustar00rootroot00000000000000/* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "init.h" #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_mount.h" #include "xfs_inode_buf.h" #include "xfs_inode_fork.h" #include "xfs_inode.h" #include "xfs_trans.h" #include "libxfs.h" /* for now */ char *progname = "libxfs"; /* default, changed by each tool */ struct cache *libxfs_bcache; /* global buffer cache */ int libxfs_bhash_size; /* #buckets in bcache */ int use_xfs_buf_lock; /* global flag: use xfs_buf_t locks for MT */ static void manage_zones(int); /* setup global zones */ kmem_zone_t *xfs_inode_zone; /* * dev_map - map open devices to fd. */ #define MAX_DEVS 10 /* arbitary maximum */ int nextfakedev = -1; /* device number to give to next fake device */ static struct dev_to_fd { dev_t dev; int fd; } dev_map[MAX_DEVS]={{0}}; /* * Checks whether a given device has a mounted, writable * filesystem, returns 1 if it does & fatal (just warns * if not fatal, but allows us to proceed). * * Useful to tools which will produce uncertain results * if the filesystem is active - repair, check, logprint. */ static int check_isactive(char *name, char *block, int fatal) { struct stat64 st; if (stat64(block, &st) < 0) return 0; if ((st.st_mode & S_IFMT) != S_IFBLK) return 0; if (platform_check_ismounted(name, block, &st, 0) == 0) return 0; return platform_check_iswritable(name, block, &st, fatal); } /* libxfs_device_to_fd: * lookup a device number in the device map * return the associated fd */ int libxfs_device_to_fd(dev_t device) { int d; for (d = 0; d < MAX_DEVS; d++) if (dev_map[d].dev == device) return dev_map[d].fd; fprintf(stderr, _("%s: %s: device %lld is not open\n"), progname, __FUNCTION__, (long long)device); exit(1); /* NOTREACHED */ } /* libxfs_device_open: * open a device and return its device number */ dev_t libxfs_device_open(char *path, int creat, int xflags, int setblksize) { dev_t dev; int fd, d, flags; int readonly, dio, excl; struct stat64 statb; readonly = (xflags & LIBXFS_ISREADONLY); excl = (xflags & LIBXFS_EXCLUSIVELY) && !creat; dio = (xflags & LIBXFS_DIRECT) && !creat && platform_direct_blockdev(); retry: flags = (readonly ? O_RDONLY : O_RDWR) | \ (creat ? (O_CREAT|O_TRUNC) : 0) | \ (dio ? O_DIRECT : 0) | \ (excl ? O_EXCL : 0); if ((fd = open(path, flags, 0666)) < 0) { if (errno == EINVAL && --dio == 0) goto retry; fprintf(stderr, _("%s: cannot open %s: %s\n"), progname, path, strerror(errno)); exit(1); } if (fstat64(fd, &statb) < 0) { fprintf(stderr, _("%s: cannot stat %s: %s\n"), progname, path, strerror(errno)); exit(1); } if (!readonly && setblksize && (statb.st_mode & S_IFMT) == S_IFBLK) { if (setblksize == 1) /* use the default blocksize */ (void)platform_set_blocksize(fd, path, statb.st_rdev, XFS_MIN_SECTORSIZE, 0); else { /* given an explicit blocksize to use */ if (platform_set_blocksize(fd, path, statb.st_rdev, setblksize, 1)) exit(1); } } /* * Get the device number from the stat buf - unless * we're not opening a real device, in which case * choose a new fake device number. */ dev = (statb.st_rdev) ? (statb.st_rdev) : (nextfakedev--); for (d = 0; d < MAX_DEVS; d++) if (dev_map[d].dev == dev) { fprintf(stderr, _("%s: device %lld is already open\n"), progname, (long long)dev); exit(1); } for (d = 0; d < MAX_DEVS; d++) if (!dev_map[d].dev) { dev_map[d].dev = dev; dev_map[d].fd = fd; return dev; } fprintf(stderr, _("%s: %s: too many open devices\n"), progname, __FUNCTION__); exit(1); /* NOTREACHED */ } void libxfs_device_close(dev_t dev) { int d; for (d = 0; d < MAX_DEVS; d++) if (dev_map[d].dev == dev) { int fd; fd = dev_map[d].fd; dev_map[d].dev = dev_map[d].fd = 0; fsync(fd); platform_flush_device(fd, dev); close(fd); return; } fprintf(stderr, _("%s: %s: device %lld is not open\n"), progname, __FUNCTION__, (long long)dev); exit(1); } static int check_open(char *path, int flags, char **rawfile, char **blockfile) { int readonly = (flags & LIBXFS_ISREADONLY); int inactive = (flags & LIBXFS_ISINACTIVE); int dangerously = (flags & LIBXFS_DANGEROUSLY); struct stat64 stbuf; if (stat64(path, &stbuf) < 0) { perror(path); return 0; } if (!(*rawfile = platform_findrawpath(path))) { fprintf(stderr, _("%s: " "can't find a character device matching %s\n"), progname, path); return 0; } if (!(*blockfile = platform_findblockpath(path))) { fprintf(stderr, _("%s: " "can't find a block device matching %s\n"), progname, path); return 0; } if (!readonly && !inactive && platform_check_ismounted(path, *blockfile, NULL, 1)) return 0; if (inactive && check_isactive(path, *blockfile, ((readonly|dangerously)?1:0))) return 0; return 1; } /* * libxfs initialization. * Caller gets a 0 on failure (and we print a message), 1 on success. */ int libxfs_init(libxfs_init_t *a) { char *blockfile; char curdir[MAXPATHLEN]; char *dname; char dpath[25]; int fd; char *logname; char logpath[25]; int needcd; char *rawfile; char *rtname; char rtpath[25]; int rval = 0; int flags; dpath[0] = logpath[0] = rtpath[0] = '\0'; dname = a->dname; logname = a->logname; rtname = a->rtname; a->dfd = a->logfd = a->rtfd = -1; a->ddev = a->logdev = a->rtdev = 0; a->dbsize = a->lbsize = a->rtbsize = 0; a->dsize = a->logBBsize = a->logBBstart = a->rtsize = 0; (void)getcwd(curdir,MAXPATHLEN); needcd = 0; fd = -1; flags = (a->isreadonly | a->isdirect); radix_tree_init(); if (a->volname) { if(!check_open(a->volname,flags,&rawfile,&blockfile)) goto done; needcd = 1; fd = open(rawfile, O_RDONLY); dname = a->dname = a->volname; a->volname = NULL; } if (dname) { if (dname[0] != '/' && needcd) chdir(curdir); if (a->disfile) { a->ddev= libxfs_device_open(dname, a->dcreat, flags, a->setblksize); a->dfd = libxfs_device_to_fd(a->ddev); } else { if (!check_open(dname, flags, &rawfile, &blockfile)) goto done; a->ddev = libxfs_device_open(rawfile, a->dcreat, flags, a->setblksize); a->dfd = libxfs_device_to_fd(a->ddev); platform_findsizes(rawfile, a->dfd, &a->dsize, &a->dbsize); } needcd = 1; } else a->dsize = 0; if (logname) { if (logname[0] != '/' && needcd) chdir(curdir); if (a->lisfile) { a->logdev = libxfs_device_open(logname, a->lcreat, flags, a->setblksize); a->logfd = libxfs_device_to_fd(a->logdev); } else { if (!check_open(logname, flags, &rawfile, &blockfile)) goto done; a->logdev = libxfs_device_open(rawfile, a->lcreat, flags, a->setblksize); a->logfd = libxfs_device_to_fd(a->logdev); platform_findsizes(rawfile, a->logfd, &a->logBBsize, &a->lbsize); } needcd = 1; } else a->logBBsize = 0; if (rtname) { if (rtname[0] != '/' && needcd) chdir(curdir); if (a->risfile) { a->rtdev = libxfs_device_open(rtname, a->rcreat, flags, a->setblksize); a->rtfd = libxfs_device_to_fd(a->rtdev); } else { if (!check_open(rtname, flags, &rawfile, &blockfile)) goto done; a->rtdev = libxfs_device_open(rawfile, a->rcreat, flags, a->setblksize); a->rtfd = libxfs_device_to_fd(a->rtdev); platform_findsizes(rawfile, a->rtfd, &a->rtsize, &a->rtbsize); } needcd = 1; } else a->rtsize = 0; if (a->dsize < 0) { fprintf(stderr, _("%s: can't get size for data subvolume\n"), progname); goto done; } if (a->logBBsize < 0) { fprintf(stderr, _("%s: can't get size for log subvolume\n"), progname); goto done; } if (a->rtsize < 0) { fprintf(stderr, _("%s: can't get size for realtime subvolume\n"), progname); goto done; } if (needcd) chdir(curdir); if (!libxfs_bhash_size) libxfs_bhash_size = LIBXFS_BHASHSIZE(sbp); libxfs_bcache = cache_init(a->bcache_flags, libxfs_bhash_size, &libxfs_bcache_operations); use_xfs_buf_lock = a->usebuflock; manage_zones(0); rval = 1; done: if (dpath[0]) unlink(dpath); if (logpath[0]) unlink(logpath); if (rtpath[0]) unlink(rtpath); if (fd >= 0) close(fd); if (!rval && a->ddev) libxfs_device_close(a->ddev); if (!rval && a->logdev) libxfs_device_close(a->logdev); if (!rval && a->rtdev) libxfs_device_close(a->rtdev); return rval; } /* * Initialize/destroy all of the zone allocators we use. */ static void manage_zones(int release) { extern kmem_zone_t *xfs_buf_zone; extern kmem_zone_t *xfs_ili_zone; extern kmem_zone_t *xfs_ifork_zone; extern kmem_zone_t *xfs_buf_item_zone; extern kmem_zone_t *xfs_da_state_zone; extern kmem_zone_t *xfs_btree_cur_zone; extern kmem_zone_t *xfs_bmap_free_item_zone; extern kmem_zone_t *xfs_log_item_desc_zone; extern void xfs_dir_startup(); if (release) { /* free zone allocation */ kmem_free(xfs_buf_zone); kmem_free(xfs_inode_zone); kmem_free(xfs_ifork_zone); kmem_free(xfs_buf_item_zone); kmem_free(xfs_da_state_zone); kmem_free(xfs_btree_cur_zone); kmem_free(xfs_bmap_free_item_zone); kmem_free(xfs_log_item_desc_zone); return; } /* otherwise initialise zone allocation */ xfs_buf_zone = kmem_zone_init(sizeof(xfs_buf_t), "xfs_buffer"); xfs_inode_zone = kmem_zone_init(sizeof(struct xfs_inode), "xfs_inode"); xfs_ifork_zone = kmem_zone_init(sizeof(xfs_ifork_t), "xfs_ifork"); xfs_ili_zone = kmem_zone_init( sizeof(xfs_inode_log_item_t), "xfs_inode_log_item"); xfs_buf_item_zone = kmem_zone_init( sizeof(xfs_buf_log_item_t), "xfs_buf_log_item"); xfs_da_state_zone = kmem_zone_init( sizeof(xfs_da_state_t), "xfs_da_state"); xfs_btree_cur_zone = kmem_zone_init( sizeof(xfs_btree_cur_t), "xfs_btree_cur"); xfs_bmap_free_item_zone = kmem_zone_init( sizeof(xfs_bmap_free_item_t), "xfs_bmap_free_item"); xfs_log_item_desc_zone = kmem_zone_init( sizeof(struct xfs_log_item_desc), "xfs_log_item_desc"); xfs_dir_startup(); } /* * Initialize realtime fields in the mount structure. */ static int rtmount_init( xfs_mount_t *mp, /* file system mount structure */ int flags) { xfs_buf_t *bp; /* buffer for last block of subvolume */ xfs_daddr_t d; /* address of last block of subvolume */ xfs_sb_t *sbp; /* filesystem superblock copy in mount */ sbp = &mp->m_sb; if (sbp->sb_rblocks == 0) return 0; if (mp->m_rtdev_targp->dev == 0 && !(flags & LIBXFS_MOUNT_DEBUGGER)) { fprintf(stderr, _("%s: filesystem has a realtime subvolume\n"), progname); return -1; } mp->m_rsumlevels = sbp->sb_rextslog + 1; mp->m_rsumsize = (uint)sizeof(xfs_suminfo_t) * mp->m_rsumlevels * sbp->sb_rbmblocks; mp->m_rsumsize = roundup(mp->m_rsumsize, sbp->sb_blocksize); mp->m_rbmip = mp->m_rsumip = NULL; /* * Allow debugger to be run without the realtime device present. */ if (flags & LIBXFS_MOUNT_DEBUGGER) return 0; /* * Check that the realtime section is an ok size. */ d = (xfs_daddr_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_rblocks); if (XFS_BB_TO_FSB(mp, d) != mp->m_sb.sb_rblocks) { fprintf(stderr, _("%s: realtime init - %llu != %llu\n"), progname, (unsigned long long) XFS_BB_TO_FSB(mp, d), (unsigned long long) mp->m_sb.sb_rblocks); return -1; } bp = libxfs_readbuf(mp->m_rtdev, d - XFS_FSB_TO_BB(mp, 1), XFS_FSB_TO_BB(mp, 1), 0, NULL); if (bp == NULL) { fprintf(stderr, _("%s: realtime size check failed\n"), progname); return -1; } libxfs_putbuf(bp); return 0; } static int libxfs_initialize_perag( xfs_mount_t *mp, xfs_agnumber_t agcount, xfs_agnumber_t *maxagi) { xfs_agnumber_t index, max_metadata; xfs_agnumber_t first_initialised = 0; xfs_perag_t *pag; xfs_agino_t agino; xfs_ino_t ino; xfs_sb_t *sbp = &mp->m_sb; int error = -ENOMEM; /* * Walk the current per-ag tree so we don't try to initialise AGs * that already exist (growfs case). Allocate and insert all the * AGs we don't find ready for initialisation. */ for (index = 0; index < agcount; index++) { pag = xfs_perag_get(mp, index); if (pag) { xfs_perag_put(pag); continue; } if (!first_initialised) first_initialised = index; pag = kmem_zalloc(sizeof(*pag), KM_MAYFAIL); if (!pag) goto out_unwind; pag->pag_agno = index; pag->pag_mount = mp; if (radix_tree_insert(&mp->m_perag_tree, index, pag)) { error = -EEXIST; goto out_unwind; } } /* * If we mount with the inode64 option, or no inode overflows * the legacy 32-bit address space clear the inode32 option. */ agino = XFS_OFFBNO_TO_AGINO(mp, sbp->sb_agblocks - 1, 0); ino = XFS_AGINO_TO_INO(mp, agcount - 1, agino); if ((mp->m_flags & XFS_MOUNT_SMALL_INUMS) && ino > XFS_MAXINUMBER_32) mp->m_flags |= XFS_MOUNT_32BITINODES; else mp->m_flags &= ~XFS_MOUNT_32BITINODES; if (mp->m_flags & XFS_MOUNT_32BITINODES) { /* * Calculate how much should be reserved for inodes to meet * the max inode percentage. */ if (mp->m_maxicount) { __uint64_t icount; icount = sbp->sb_dblocks * sbp->sb_imax_pct; do_div(icount, 100); icount += sbp->sb_agblocks - 1; do_div(icount, sbp->sb_agblocks); max_metadata = icount; } else { max_metadata = agcount; } for (index = 0; index < agcount; index++) { ino = XFS_AGINO_TO_INO(mp, index, agino); if (ino > XFS_MAXINUMBER_32) { index++; break; } pag = xfs_perag_get(mp, index); pag->pagi_inodeok = 1; if (index < max_metadata) pag->pagf_metadata = 1; xfs_perag_put(pag); } } else { for (index = 0; index < agcount; index++) { pag = xfs_perag_get(mp, index); pag->pagi_inodeok = 1; xfs_perag_put(pag); } } if (maxagi) *maxagi = index; return 0; out_unwind: kmem_free(pag); for (; index > first_initialised; index--) { pag = radix_tree_delete(&mp->m_perag_tree, index); kmem_free(pag); } return error; } static struct xfs_buftarg * libxfs_buftarg_alloc( struct xfs_mount *mp, dev_t dev) { struct xfs_buftarg *btp; btp = malloc(sizeof(*btp)); if (!btp) { fprintf(stderr, _("%s: buftarg init failed\n"), progname); exit(1); } btp->bt_mount = mp; btp->dev = dev; return btp; } void libxfs_buftarg_init( struct xfs_mount *mp, dev_t dev, dev_t logdev, dev_t rtdev) { if (mp->m_ddev_targp) { /* should already have all buftargs initialised */ if (mp->m_ddev_targp->dev != dev || mp->m_ddev_targp->bt_mount != mp) { fprintf(stderr, _("%s: bad buftarg reinit, ddev\n"), progname); exit(1); } if (!logdev || logdev == dev) { if (mp->m_logdev_targp != mp->m_ddev_targp) { fprintf(stderr, _("%s: bad buftarg reinit, ldev mismatch\n"), progname); exit(1); } } else if (mp->m_logdev_targp->dev != logdev || mp->m_logdev_targp->bt_mount != mp) { fprintf(stderr, _("%s: bad buftarg reinit, logdev\n"), progname); exit(1); } if (rtdev && (mp->m_rtdev_targp->dev != rtdev || mp->m_rtdev_targp->bt_mount != mp)) { fprintf(stderr, _("%s: bad buftarg reinit, rtdev\n"), progname); exit(1); } return; } mp->m_ddev_targp = libxfs_buftarg_alloc(mp, dev); if (!logdev || logdev == dev) mp->m_logdev_targp = mp->m_ddev_targp; else mp->m_logdev_targp = libxfs_buftarg_alloc(mp, logdev); mp->m_rtdev_targp = libxfs_buftarg_alloc(mp, rtdev); } /* * Mount structure initialization, provides a filled-in xfs_mount_t * such that the numerous XFS_* macros can be used. If dev is zero, * no IO will be performed (no size checks, read root inodes). */ xfs_mount_t * libxfs_mount( xfs_mount_t *mp, xfs_sb_t *sb, dev_t dev, dev_t logdev, dev_t rtdev, int flags) { xfs_daddr_t d; xfs_buf_t *bp; xfs_sb_t *sbp; int error; libxfs_buftarg_init(mp, dev, logdev, rtdev); mp->m_flags = (LIBXFS_MOUNT_32BITINODES|LIBXFS_MOUNT_32BITINOOPT); mp->m_sb = *sb; INIT_RADIX_TREE(&mp->m_perag_tree, GFP_KERNEL); sbp = &(mp->m_sb); xfs_sb_mount_common(mp, sb); xfs_alloc_compute_maxlevels(mp); xfs_bmap_compute_maxlevels(mp, XFS_DATA_FORK); xfs_bmap_compute_maxlevels(mp, XFS_ATTR_FORK); xfs_ialloc_compute_maxlevels(mp); if (sbp->sb_imax_pct) { /* Make sure the maximum inode count is a multiple of the * units we allocate inodes in. */ mp->m_maxicount = (sbp->sb_dblocks * sbp->sb_imax_pct) / 100; mp->m_maxicount = ((mp->m_maxicount / mp->m_ialloc_blks) * mp->m_ialloc_blks) << sbp->sb_inopblog; } else mp->m_maxicount = 0; mp->m_inode_cluster_size = XFS_INODE_BIG_CLUSTER_SIZE; /* * Set whether we're using stripe alignment. */ if (xfs_sb_version_hasdalign(&mp->m_sb)) { mp->m_dalign = sbp->sb_unit; mp->m_swidth = sbp->sb_width; } /* * Set whether we're using inode alignment. */ if (xfs_sb_version_hasalign(&mp->m_sb) && mp->m_sb.sb_inoalignmt >= XFS_B_TO_FSBT(mp, mp->m_inode_cluster_size)) mp->m_inoalign_mask = mp->m_sb.sb_inoalignmt - 1; else mp->m_inoalign_mask = 0; /* * If we are using stripe alignment, check whether * the stripe unit is a multiple of the inode alignment */ if (mp->m_dalign && mp->m_inoalign_mask && !(mp->m_dalign & mp->m_inoalign_mask)) mp->m_sinoalign = mp->m_dalign; else mp->m_sinoalign = 0; /* * Check that the data (and log if separate) are an ok size. */ d = (xfs_daddr_t) XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks); if (XFS_BB_TO_FSB(mp, d) != mp->m_sb.sb_dblocks) { fprintf(stderr, _("%s: size check failed\n"), progname); if (!(flags & LIBXFS_MOUNT_DEBUGGER)) return NULL; } /* * We automatically convert v1 inodes to v2 inodes now, so if * the NLINK bit is not set we can't operate on the filesystem. */ if (!(sbp->sb_versionnum & XFS_SB_VERSION_NLINKBIT)) { fprintf(stderr, _( "%s: V1 inodes unsupported. Please try an older xfsprogs.\n"), progname); exit(1); } /* Check for supported directory formats */ if (!(sbp->sb_versionnum & XFS_SB_VERSION_DIRV2BIT)) { fprintf(stderr, _( "%s: V1 directories unsupported. Please try an older xfsprogs.\n"), progname); exit(1); } /* check for unsupported other features */ if (!xfs_sb_good_version(sbp)) { fprintf(stderr, _( "%s: Unsupported features detected. Please try a newer xfsprogs.\n"), progname); exit(1); } xfs_da_mount(mp); if (xfs_sb_version_hasattr2(&mp->m_sb)) mp->m_flags |= LIBXFS_MOUNT_ATTR2; /* Initialize the precomputed transaction reservations values */ xfs_trans_init(mp); if (dev == 0) /* maxtrres, we have no device so leave now */ return mp; bp = libxfs_readbuf(mp->m_dev, d - XFS_FSS_TO_BB(mp, 1), XFS_FSS_TO_BB(mp, 1), !(flags & LIBXFS_MOUNT_DEBUGGER), NULL); if (!bp) { fprintf(stderr, _("%s: data size check failed\n"), progname); if (!(flags & LIBXFS_MOUNT_DEBUGGER)) return NULL; } else libxfs_putbuf(bp); if (mp->m_logdev_targp->dev && mp->m_logdev_targp->dev != mp->m_ddev_targp->dev) { d = (xfs_daddr_t) XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks); if ( (XFS_BB_TO_FSB(mp, d) != mp->m_sb.sb_logblocks) || (!(bp = libxfs_readbuf(mp->m_logdev_targp, d - XFS_FSB_TO_BB(mp, 1), XFS_FSB_TO_BB(mp, 1), !(flags & LIBXFS_MOUNT_DEBUGGER), NULL))) ) { fprintf(stderr, _("%s: log size checks failed\n"), progname); if (!(flags & LIBXFS_MOUNT_DEBUGGER)) return NULL; } if (bp) libxfs_putbuf(bp); } /* Initialize realtime fields in the mount structure */ if (rtmount_init(mp, flags)) { fprintf(stderr, _("%s: realtime device init failed\n"), progname); return NULL; } error = libxfs_initialize_perag(mp, sbp->sb_agcount, &mp->m_maxagi); if (error) { fprintf(stderr, _("%s: perag init failed\n"), progname); exit(1); } return mp; } void libxfs_rtmount_destroy(xfs_mount_t *mp) { if (mp->m_rsumip) IRELE(mp->m_rsumip); if (mp->m_rbmip) IRELE(mp->m_rbmip); mp->m_rsumip = mp->m_rbmip = NULL; } /* * Release any resource obtained during a mount. */ void libxfs_umount(xfs_mount_t *mp) { struct xfs_perag *pag; int agno; libxfs_rtmount_destroy(mp); libxfs_bcache_purge(); for (agno = 0; agno < mp->m_maxagi; agno++) { pag = radix_tree_delete(&mp->m_perag_tree, agno); kmem_free(pag); } kmem_free(mp->m_attr_geo); kmem_free(mp->m_dir_geo); kmem_free(mp->m_rtdev_targp); if (mp->m_logdev_targp != mp->m_ddev_targp) kmem_free(mp->m_logdev_targp); kmem_free(mp->m_ddev_targp); } /* * Release any global resources used by libxfs. */ void libxfs_destroy(void) { manage_zones(1); cache_destroy(libxfs_bcache); } int libxfs_device_alignment(void) { return platform_align_blockdev(); } void libxfs_report(FILE *fp) { time_t t; char *c; cache_report(fp, "libxfs_bcache", libxfs_bcache); t = time(NULL); c = asctime(localtime(&t)); fprintf(fp, "%s", c); } int libxfs_nproc(void) { return platform_nproc(); } unsigned long libxfs_physmem(void) { return platform_physmem(); } partclone-0.2.86/src/xfs/init.h000066400000000000000000000027201262102574200163030ustar00rootroot00000000000000/* * Copyright (c) 2000-2006 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef LIBXFS_INIT_H #define LIBXFS_INIT_H struct stat64; extern int platform_check_ismounted (char *path, char *block, struct stat64 *sptr, int verbose); extern int platform_check_iswritable (char *path, char *block, struct stat64 *sptr, int fatal); extern int platform_set_blocksize (int fd, char *path, dev_t device, int bsz, int fatal); extern void platform_flush_device (int fd, dev_t device); extern char *platform_findrawpath(char *path); extern char *platform_findrawpath (char *path); extern char *platform_findblockpath (char *path); extern int platform_direct_blockdev (void); extern int platform_align_blockdev (void); extern unsigned long platform_physmem(void); /* in kilobytes */ extern int platform_has_uuid; #endif /* LIBXFS_INIT_H */ partclone-0.2.86/src/xfs/input.h000066400000000000000000000036321262102574200165020ustar00rootroot00000000000000/* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __INPUT_H__ #define __INPUT_H__ #include #include #include #include "project.h" #include extern char **breakline(char *input, int *count); extern void doneline(char *input, char **vec); extern char *fetchline(void); extern long long cvtnum(size_t blocksize, size_t sectorsize, char *s); extern void cvtstr(double value, char *str, size_t sz); extern unsigned long cvttime(char *s); extern struct timeval tadd(struct timeval t1, struct timeval t2); extern struct timeval tsub(struct timeval t1, struct timeval t2); extern double tdiv(double value, struct timeval tv); enum { DEFAULT_TIME = 0x0, TERSE_FIXED_TIME = 0x1, VERBOSE_FIXED_TIME = 0x2 }; extern void timestr(struct timeval *tv, char *str, size_t sz, int flags); extern uid_t uid_from_string(char *user); extern gid_t gid_from_string(char *group); extern prid_t prid_from_string(char *project); extern bool isdigits_only(const char *str); #define HAVE_FTW_H 1 /* TODO: configure me */ #ifdef HAVE_FTW_H #include #else struct FTW; struct stat; extern int nftw( char *dir, int (*fn)(const char *, const struct stat *, int, struct FTW *), int depth, int flags); #endif #endif /* __INPUT_H__ */ partclone-0.2.86/src/xfs/jdm.h000066400000000000000000000046021262102574200161130ustar00rootroot00000000000000/* * Copyright (c) 2000-2002, 2005 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __JDM_H__ #define __JDM_H__ typedef int intgen_t; typedef void jdm_fshandle_t; /* filesystem handle */ typedef void jdm_filehandle_t; /* filehandle */ struct xfs_bstat; struct attrlist_cursor; struct parent; extern jdm_fshandle_t * jdm_getfshandle( char *mntpnt); extern void jdm_new_filehandle( jdm_filehandle_t **handlep, /* new filehandle */ size_t *hlen, /* new filehandle size */ jdm_fshandle_t *fshandlep, /* filesystem filehandle */ struct xfs_bstat *sp); /* bulkstat info */ extern void jdm_delete_filehandle( jdm_filehandle_t *handlep,/* filehandle to delete */ size_t hlen); /* filehandle size */ extern intgen_t jdm_open( jdm_fshandle_t *fshandlep, struct xfs_bstat *sp, intgen_t oflags); extern intgen_t jdm_readlink( jdm_fshandle_t *fshandlep, struct xfs_bstat *sp, char *bufp, size_t bufsz); extern intgen_t jdm_attr_multi( jdm_fshandle_t *fshp, xfs_bstat_t *statp, char *bufp, int rtrvcnt, int flags); extern intgen_t jdm_attr_list( jdm_fshandle_t *fshp, xfs_bstat_t *statp, char *bufp, size_t bufsz, int flags, struct attrlist_cursor *cursor); extern int jdm_parents( jdm_fshandle_t *fshp, xfs_bstat_t *statp, struct parent *bufp, size_t bufsz, unsigned int *count); extern int jdm_parentpaths( jdm_fshandle_t *fshp, xfs_bstat_t *statp, struct parent *bufp, size_t bufsz, unsigned int *count); /* macro for determining the size of a structure member */ #define sizeofmember( t, m ) sizeof( ( ( t * )0 )->m ) /* macro for calculating the offset of a structure member */ #define offsetofmember( t, m ) ( ( size_t )( char * )&( ( ( t * )0 )->m ) ) #endif /* __JDM_H__ */ partclone-0.2.86/src/xfs/kmem.c000066400000000000000000000027261262102574200162720ustar00rootroot00000000000000 #include "libxfs_priv.h" /* * Simple memory interface */ kmem_zone_t * kmem_zone_init(int size, char *name) { kmem_zone_t *ptr = malloc(sizeof(kmem_zone_t)); if (ptr == NULL) { fprintf(stderr, _("%s: zone init failed (%s, %d bytes): %s\n"), progname, name, (int)sizeof(kmem_zone_t), strerror(errno)); exit(1); } ptr->zone_unitsize = size; ptr->zone_name = name; ptr->allocated = 0; return ptr; } void * kmem_zone_alloc(kmem_zone_t *zone, int flags) { void *ptr = malloc(zone->zone_unitsize); if (ptr == NULL) { fprintf(stderr, _("%s: zone alloc failed (%s, %d bytes): %s\n"), progname, zone->zone_name, zone->zone_unitsize, strerror(errno)); exit(1); } zone->allocated++; return ptr; } void * kmem_zone_zalloc(kmem_zone_t *zone, int flags) { void *ptr = kmem_zone_alloc(zone, flags); memset(ptr, 0, zone->zone_unitsize); return ptr; } void * kmem_alloc(size_t size, int flags) { void *ptr = malloc(size); if (ptr == NULL) { fprintf(stderr, _("%s: malloc failed (%d bytes): %s\n"), progname, (int)size, strerror(errno)); exit(1); } return ptr; } void * kmem_zalloc(size_t size, int flags) { void *ptr = kmem_alloc(size, flags); memset(ptr, 0, size); return ptr; } void * kmem_realloc(void *ptr, size_t new_size, size_t old_size, int flags) { ptr = realloc(ptr, new_size); if (ptr == NULL) { fprintf(stderr, _("%s: realloc failed (%d bytes): %s\n"), progname, (int)new_size, strerror(errno)); exit(1); } return ptr; } partclone-0.2.86/src/xfs/kmem.h000066400000000000000000000030341262102574200162700ustar00rootroot00000000000000/* * Copyright (c) 2008 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __KMEM_H__ #define __KMEM_H__ #define KM_SLEEP 0x0001u #define KM_NOSLEEP 0x0002u #define KM_NOFS 0x0004u #define KM_MAYFAIL 0x0008u #define KM_LARGE 0x0010u typedef struct kmem_zone { int zone_unitsize; /* Size in bytes of zone unit */ char *zone_name; /* tag name */ int allocated; /* debug: How many currently allocated */ } kmem_zone_t; extern kmem_zone_t *kmem_zone_init(int, char *); extern void *kmem_zone_alloc(kmem_zone_t *, int); extern void *kmem_zone_zalloc(kmem_zone_t *, int); static inline void kmem_zone_free(kmem_zone_t *zone, void *ptr) { zone->allocated--; free(ptr); } extern void *kmem_alloc(size_t, int); extern void *kmem_zalloc(size_t, int); static inline void kmem_free(void *ptr) { free(ptr); } extern void *kmem_realloc(void *, size_t, size_t, int); #endif partclone-0.2.86/src/xfs/libxfs.h000066400000000000000000000174041262102574200166340ustar00rootroot00000000000000/* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __LIBXFS_H__ #define __LIBXFS_H__ #include "libxfs_api_defs.h" #include "platform_defs.h" #include "xfs.h" #include "list.h" #include "hlist.h" #include "cache.h" #include "bitops.h" #include "kmem.h" #include "radix-tree.h" #include "atomic.h" #include "xfs_types.h" #include "xfs_fs.h" #include "xfs_arch.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_quota_defs.h" #include "xfs_trans_resv.h" /* CRC stuff, buffer API dependent on it */ extern uint32_t crc32_le(uint32_t crc, unsigned char const *p, size_t len); extern uint32_t crc32c_le(uint32_t crc, unsigned char const *p, size_t len); #define crc32(c,p,l) crc32_le((c),(unsigned char const *)(p),(l)) #define crc32c(c,p,l) crc32c_le((c),(unsigned char const *)(p),(l)) #include "xfs_cksum.h" /* * This mirrors the kernel include for xfs_buf.h - it's implicitly included in * every files via a similar include in the kernel xfs_linux.h. */ #include "libxfs_io.h" #include "xfs_bit.h" #include "xfs_sb.h" #include "xfs_mount.h" #include "xfs_da_format.h" #include "xfs_da_btree.h" #include "xfs_dir2.h" #include "xfs_bmap_btree.h" #include "xfs_alloc_btree.h" #include "xfs_ialloc_btree.h" #include "xfs_attr_sf.h" #include "xfs_inode_fork.h" #include "xfs_inode_buf.h" #include "xfs_inode.h" #include "xfs_alloc.h" #include "xfs_btree.h" #include "xfs_btree_trace.h" #include "xfs_bmap.h" #include "xfs_trace.h" #include "xfs_trans.h" #ifndef ARRAY_SIZE #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) #endif #ifndef XFS_SUPER_MAGIC #define XFS_SUPER_MAGIC 0x58465342 #endif #define xfs_isset(a,i) ((a)[(i)/(sizeof((a))*NBBY)] & (1<<((i)%(sizeof((a))*NBBY)))) /* * Argument structure for libxfs_init(). */ typedef struct { /* input parameters */ char *volname; /* pathname of volume */ char *dname; /* pathname of data "subvolume" */ char *logname; /* pathname of log "subvolume" */ char *rtname; /* pathname of realtime "subvolume" */ int isreadonly; /* filesystem is only read in applic */ int isdirect; /* we can attempt to use direct I/O */ int disfile; /* data "subvolume" is a regular file */ int dcreat; /* try to create data subvolume */ int lisfile; /* log "subvolume" is a regular file */ int lcreat; /* try to create log subvolume */ int risfile; /* realtime "subvolume" is a reg file */ int rcreat; /* try to create realtime subvolume */ int setblksize; /* attempt to set device blksize */ int usebuflock; /* lock xfs_buf_t's - for MT usage */ /* output results */ dev_t ddev; /* device for data subvolume */ dev_t logdev; /* device for log subvolume */ dev_t rtdev; /* device for realtime subvolume */ long long dsize; /* size of data subvolume (BBs) */ long long logBBsize; /* size of log subvolume (BBs) */ /* (blocks allocated for use as * log is stored in mount structure) */ long long logBBstart; /* start block of log subvolume (BBs) */ long long rtsize; /* size of realtime subvolume (BBs) */ int dbsize; /* data subvolume device blksize */ int lbsize; /* log subvolume device blksize */ int rtbsize; /* realtime subvolume device blksize */ int dfd; /* data subvolume file descriptor */ int logfd; /* log subvolume file descriptor */ int rtfd; /* realtime subvolume file descriptor */ int icache_flags; /* cache init flags */ int bcache_flags; /* cache init flags */ } libxfs_init_t; #define LIBXFS_EXIT_ON_FAILURE 0x0001 /* exit the program if a call fails */ #define LIBXFS_ISREADONLY 0x0002 /* disallow all mounted filesystems */ #define LIBXFS_ISINACTIVE 0x0004 /* allow mounted only if mounted ro */ #define LIBXFS_DANGEROUSLY 0x0008 /* repairing a device mounted ro */ #define LIBXFS_EXCLUSIVELY 0x0010 /* disallow other accesses (O_EXCL) */ #define LIBXFS_DIRECT 0x0020 /* can use direct I/O, not buffered */ extern char *progname; extern int libxfs_init (libxfs_init_t *); extern void libxfs_destroy (void); extern int libxfs_device_to_fd (dev_t); extern dev_t libxfs_device_open (char *, int, int, int); extern void libxfs_device_zero(struct xfs_buftarg *, xfs_daddr_t, uint); extern void libxfs_device_close (dev_t); extern int libxfs_device_alignment (void); extern void libxfs_report(FILE *); extern void platform_findsizes(char *path, int fd, long long *sz, int *bsz); extern int platform_nproc(void); /* check or write log footer: specify device, log size in blocks & uuid */ typedef char *(libxfs_get_block_t)(char *, int, void *); extern int libxfs_log_clear (struct xfs_buftarg *, xfs_daddr_t, uint, uuid_t *, int, int, int); extern int libxfs_log_header (char *, uuid_t *, int, int, int, libxfs_get_block_t *, void *); /* Shared utility routines */ extern unsigned int libxfs_log2_roundup(unsigned int i); extern int libxfs_alloc_file_space (struct xfs_inode *, xfs_off_t, xfs_off_t, int, int); extern int libxfs_bmap_finish(xfs_trans_t **, xfs_bmap_free_t *, int *); extern void libxfs_fs_repair_cmn_err(int, struct xfs_mount *, char *, ...); extern void libxfs_fs_cmn_err(int, struct xfs_mount *, char *, ...); /* XXX: this is messy and needs fixing */ #ifndef __LIBXFS_INTERNAL_XFS_H__ extern void cmn_err(int, char *, ...); enum ce { CE_DEBUG, CE_CONT, CE_NOTE, CE_WARN, CE_ALERT, CE_PANIC }; #endif extern int libxfs_nproc(void); extern unsigned long libxfs_physmem(void); /* in kilobytes */ #include "xfs_ialloc.h" #include "xfs_attr_leaf.h" #include "xfs_attr_remote.h" #include "xfs_trans_space.h" #define XFS_INOBT_IS_FREE_DISK(rp,i) \ ((be64_to_cpu((rp)->ir_free) & XFS_INOBT_MASK(i)) != 0) static inline bool xfs_inobt_is_sparse_disk( struct xfs_inobt_rec *rp, int offset) { int spshift; uint16_t holemask; holemask = be16_to_cpu(rp->ir_u.sp.ir_holemask); spshift = offset / XFS_INODES_PER_HOLEMASK_BIT; if ((1 << spshift) & holemask) return true; return false; } static inline void libxfs_bmbt_disk_get_all( struct xfs_bmbt_rec *rp, struct xfs_bmbt_irec *irec) { struct xfs_bmbt_rec_host hrec; hrec.l0 = be64_to_cpu(rp->l0); hrec.l1 = be64_to_cpu(rp->l1); libxfs_bmbt_get_all(&hrec, irec); } /* XXX: this is clearly a bug - a shared header needs to export this */ /* xfs_rtalloc.c */ int libxfs_rtfree_extent(struct xfs_trans *, xfs_rtblock_t, xfs_extlen_t); /* XXX: need parts of xfs_attr.h in userspace */ #define LIBXFS_ATTR_ROOT 0x0002 /* use attrs in root namespace */ #define LIBXFS_ATTR_SECURE 0x0008 /* use attrs in security namespace */ #define LIBXFS_ATTR_CREATE 0x0010 /* create, but fail if attr exists */ #define LIBXFS_ATTR_REPLACE 0x0020 /* set, but fail if attr not exists */ int xfs_attr_remove(struct xfs_inode *dp, const unsigned char *name, int flags); int xfs_attr_set(struct xfs_inode *dp, const unsigned char *name, unsigned char *value, int valuelen, int flags); #endif /* __LIBXFS_H__ */ partclone-0.2.86/src/xfs/libxfs_api_defs.h000066400000000000000000000110001262102574200204500ustar00rootroot00000000000000/* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __LIBXFS_API_DEFS_H__ #define __LIBXFS_API_DEFS_H__ /* * This file defines all the kernel based functions we expose to userspace * via the libxfs_* namespace. This is kept in a separate header file so * it can be included in both the internal and external libxfs header files * without introducing any depenencies between the two. */ #define xfs_highbit32 libxfs_highbit32 #define xfs_highbit64 libxfs_highbit64 #define xfs_fs_repair_cmn_err libxfs_fs_repair_cmn_err #define xfs_fs_cmn_err libxfs_fs_cmn_err #define xfs_trans_alloc libxfs_trans_alloc #define xfs_trans_add_item libxfs_trans_add_item #define xfs_trans_bhold libxfs_trans_bhold #define xfs_trans_binval libxfs_trans_binval #define xfs_trans_bjoin libxfs_trans_bjoin #define xfs_trans_brelse libxfs_trans_brelse #define xfs_trans_commit libxfs_trans_commit #define xfs_trans_cancel libxfs_trans_cancel #define xfs_trans_del_item libxfs_trans_del_item #define xfs_trans_get_buf libxfs_trans_get_buf #define xfs_trans_getsb libxfs_trans_getsb #define xfs_trans_iget libxfs_trans_iget #define xfs_trans_ichgtime libxfs_trans_ichgtime #define xfs_trans_ijoin libxfs_trans_ijoin #define xfs_trans_ijoin_ref libxfs_trans_ijoin_ref #define xfs_trans_init libxfs_trans_init #define xfs_trans_inode_alloc_buf libxfs_trans_inode_alloc_buf #define xfs_trans_log_buf libxfs_trans_log_buf #define xfs_trans_log_inode libxfs_trans_log_inode #define xfs_trans_mod_sb libxfs_trans_mod_sb #define xfs_trans_read_buf libxfs_trans_read_buf #define xfs_trans_read_buf_map libxfs_trans_read_buf_map #define xfs_trans_roll libxfs_trans_roll #define xfs_trans_get_buf_map libxfs_trans_get_buf_map #define xfs_trans_reserve libxfs_trans_reserve #define xfs_trans_resv_calc libxfs_trans_resv_calc #define xfs_attr_get libxfs_attr_get #define xfs_attr_set libxfs_attr_set #define xfs_attr_remove libxfs_attr_remove #define xfs_attr_leaf_newentsize libxfs_attr_leaf_newentsize #define xfs_alloc_fix_freelist libxfs_alloc_fix_freelist #define xfs_bmap_cancel libxfs_bmap_cancel #define xfs_bmap_last_offset libxfs_bmap_last_offset #define xfs_bmap_search_extents libxfs_bmap_search_extents #define xfs_bmap_finish libxfs_bmap_finish #define xfs_bmapi_write libxfs_bmapi_write #define xfs_bmapi_read libxfs_bmapi_read #define xfs_bunmapi libxfs_bunmapi #define xfs_bmbt_get_all libxfs_bmbt_get_all #define xfs_rtfree_extent libxfs_rtfree_extent #define xfs_da_brelse libxfs_da_brelse #define xfs_da_hashname libxfs_da_hashname #define xfs_da_shrink_inode libxfs_da_shrink_inode #define xfs_da_read_buf libxfs_da_read_buf #define xfs_dir_createname libxfs_dir_createname #define xfs_dir_init libxfs_dir_init #define xfs_dir_lookup libxfs_dir_lookup #define xfs_dir_replace libxfs_dir_replace #define xfs_dir2_isblock libxfs_dir2_isblock #define xfs_dir2_isleaf libxfs_dir2_isleaf #define __xfs_dir2_data_freescan libxfs_dir2_data_freescan #define xfs_dir2_data_log_entry libxfs_dir2_data_log_entry #define xfs_dir2_data_log_header libxfs_dir2_data_log_header #define xfs_dir2_data_make_free libxfs_dir2_data_make_free #define xfs_dir2_data_use_free libxfs_dir2_data_use_free #define xfs_dir2_shrink_inode libxfs_dir2_shrink_inode #define xfs_dinode_from_disk libxfs_dinode_from_disk #define xfs_dinode_to_disk libxfs_dinode_to_disk #define xfs_dinode_calc_crc libxfs_dinode_calc_crc #define xfs_idata_realloc libxfs_idata_realloc #define xfs_idestroy_fork libxfs_idestroy_fork #define xfs_log_sb libxfs_log_sb #define xfs_sb_from_disk libxfs_sb_from_disk #define xfs_sb_quota_from_disk libxfs_sb_quota_from_disk #define xfs_sb_to_disk libxfs_sb_to_disk #define xfs_symlink_blocks libxfs_symlink_blocks #define xfs_symlink_hdr_ok libxfs_symlink_hdr_ok #define xfs_verify_cksum libxfs_verify_cksum #endif /* __LIBXFS_API_DEFS_H__ */ partclone-0.2.86/src/xfs/libxfs_io.h000066400000000000000000000175771262102574200173360ustar00rootroot00000000000000/* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __LIBXFS_IO_H_ #define __LIBXFS_IO_H_ /* * Kernel equivalent buffer based I/O interface */ struct xfs_buf; struct xfs_mount; struct xfs_perag; /* * IO verifier callbacks need the xfs_mount pointer, so we have to behave * somewhat like the kernel now for userspace IO in terms of having buftarg * based devices... */ struct xfs_buftarg { struct xfs_mount *bt_mount; dev_t dev; }; extern void libxfs_buftarg_init(struct xfs_mount *mp, dev_t ddev, dev_t logdev, dev_t rtdev); #define LIBXFS_BBTOOFF64(bbs) (((xfs_off_t)(bbs)) << BBSHIFT) #define XB_PAGES 2 struct xfs_buf_map { xfs_daddr_t bm_bn; /* block number for I/O */ int bm_len; /* size of I/O */ }; #define DEFINE_SINGLE_BUF_MAP(map, blkno, numblk) \ struct xfs_buf_map (map) = { .bm_bn = (blkno), .bm_len = (numblk) }; struct xfs_buf_ops { void (*verify_read)(struct xfs_buf *); void (*verify_write)(struct xfs_buf *); }; typedef struct xfs_buf { struct cache_node b_node; unsigned int b_flags; xfs_daddr_t b_bn; unsigned b_bcount; unsigned int b_length; struct xfs_buftarg *b_target; #define b_dev b_target->dev pthread_mutex_t b_lock; pthread_t b_holder; unsigned int b_recur; void *b_fspriv; void *b_fsprivate2; void *b_fsprivate3; void *b_addr; int b_error; const struct xfs_buf_ops *b_ops; struct xfs_perag *b_pag; struct xfs_buf_map *b_map; int b_nmaps; #ifdef XFS_BUF_TRACING struct list_head b_lock_list; const char *b_func; const char *b_file; int b_line; #endif } xfs_buf_t; enum xfs_buf_flags_t { /* b_flags bits */ LIBXFS_B_EXIT = 0x0001, /* ==LIBXFS_EXIT_ON_FAILURE */ LIBXFS_B_DIRTY = 0x0002, /* buffer has been modified */ LIBXFS_B_STALE = 0x0004, /* buffer marked as invalid */ LIBXFS_B_UPTODATE = 0x0008, /* buffer is sync'd to disk */ LIBXFS_B_DISCONTIG = 0x0010, /* discontiguous buffer */ LIBXFS_B_UNCHECKED = 0x0020, /* needs verification */ }; #define XFS_BUF_DADDR_NULL ((xfs_daddr_t) (-1LL)) #define XFS_BUF_PTR(bp) ((char *)(bp)->b_addr) #define xfs_buf_offset(bp, offset) ((bp)->b_addr + (offset)) #define XFS_BUF_ADDR(bp) ((bp)->b_bn) #define XFS_BUF_SIZE(bp) ((bp)->b_bcount) #define XFS_BUF_COUNT(bp) ((bp)->b_bcount) #define XFS_BUF_TARGET(bp) ((bp)->b_dev) #define XFS_BUF_SET_PTR(bp,p,cnt) ({ \ (bp)->b_addr = (char *)(p); \ XFS_BUF_SET_COUNT(bp,cnt); \ }) #define XFS_BUF_SET_ADDR(bp,blk) ((bp)->b_bn = (blk)) #define XFS_BUF_SET_COUNT(bp,cnt) ((bp)->b_bcount = (cnt)) #define XFS_BUF_FSPRIVATE(bp,type) ((type)(bp)->b_fspriv) #define XFS_BUF_SET_FSPRIVATE(bp,val) (bp)->b_fspriv = (void *)(val) #define XFS_BUF_FSPRIVATE2(bp,type) ((type)(bp)->b_fsprivate2) #define XFS_BUF_SET_FSPRIVATE2(bp,val) (bp)->b_fsprivate2 = (void *)(val) #define XFS_BUF_FSPRIVATE3(bp,type) ((type)(bp)->b_fsprivate3) #define XFS_BUF_SET_FSPRIVATE3(bp,val) (bp)->b_fsprivate3 = (void *)(val) #define XFS_BUF_SET_PRIORITY(bp,pri) cache_node_set_priority( \ libxfs_bcache, \ (struct cache_node *)(bp), \ (pri)) #define XFS_BUF_PRIORITY(bp) (cache_node_get_priority( \ (struct cache_node *)(bp))) #define xfs_buf_set_ref(bp,ref) ((void) 0) #define xfs_buf_ioerror(bp,err) ((bp)->b_error = (err)) #define xfs_daddr_to_agno(mp,d) \ ((xfs_agnumber_t)(XFS_BB_TO_FSBT(mp, d) / (mp)->m_sb.sb_agblocks)) #define xfs_daddr_to_agbno(mp,d) \ ((xfs_agblock_t)(XFS_BB_TO_FSBT(mp, d) % (mp)->m_sb.sb_agblocks)) /* Buffer Cache Interfaces */ extern struct cache *libxfs_bcache; extern struct cache_operations libxfs_bcache_operations; #define LIBXFS_GETBUF_TRYLOCK (1 << 0) #ifdef XFS_BUF_TRACING #define libxfs_readbuf(dev, daddr, len, flags, ops) \ libxfs_trace_readbuf(__FUNCTION__, __FILE__, __LINE__, \ (dev), (daddr), (len), (flags), (ops)) #define libxfs_readbuf_map(dev, map, nmaps, flags, ops) \ libxfs_trace_readbuf_map(__FUNCTION__, __FILE__, __LINE__, \ (dev), (map), (nmaps), (flags), (ops)) #define libxfs_writebuf(buf, flags) \ libxfs_trace_writebuf(__FUNCTION__, __FILE__, __LINE__, \ (buf), (flags)) #define libxfs_getbuf(dev, daddr, len) \ libxfs_trace_getbuf(__FUNCTION__, __FILE__, __LINE__, \ (dev), (daddr), (len)) #define libxfs_getbuf_map(dev, map, nmaps, flags) \ libxfs_trace_getbuf_map(__FUNCTION__, __FILE__, __LINE__, \ (dev), (map), (nmaps), (flags)) #define libxfs_getbuf_flags(dev, daddr, len, flags) \ libxfs_trace_getbuf_flags(__FUNCTION__, __FILE__, __LINE__, \ (dev), (daddr), (len), (flags)) #define libxfs_putbuf(buf) \ libxfs_trace_putbuf(__FUNCTION__, __FILE__, __LINE__, (buf)) extern xfs_buf_t *libxfs_trace_readbuf(const char *, const char *, int, struct xfs_buftarg *, xfs_daddr_t, int, int, const struct xfs_buf_ops *); extern xfs_buf_t *libxfs_trace_readbuf_map(const char *, const char *, int, struct xfs_buftarg *, struct xfs_buf_map *, int, int, const struct xfs_buf_ops *); extern int libxfs_trace_writebuf(const char *, const char *, int, xfs_buf_t *, int); extern xfs_buf_t *libxfs_trace_getbuf(const char *, const char *, int, struct xfs_buftarg *, xfs_daddr_t, int); extern xfs_buf_t *libxfs_trace_getbuf_map(const char *, const char *, int, struct xfs_buftarg *, struct xfs_buf_map *, int, int); extern xfs_buf_t *libxfs_trace_getbuf_flags(const char *, const char *, int, struct xfs_buftarg *, xfs_daddr_t, int, unsigned int); extern void libxfs_trace_putbuf (const char *, const char *, int, xfs_buf_t *); #else extern xfs_buf_t *libxfs_readbuf(struct xfs_buftarg *, xfs_daddr_t, int, int, const struct xfs_buf_ops *); extern xfs_buf_t *libxfs_readbuf_map(struct xfs_buftarg *, struct xfs_buf_map *, int, int, const struct xfs_buf_ops *); extern int libxfs_writebuf(xfs_buf_t *, int); extern xfs_buf_t *libxfs_getbuf(struct xfs_buftarg *, xfs_daddr_t, int); extern xfs_buf_t *libxfs_getbuf_map(struct xfs_buftarg *, struct xfs_buf_map *, int, int); extern xfs_buf_t *libxfs_getbuf_flags(struct xfs_buftarg *, xfs_daddr_t, int, unsigned int); extern void libxfs_putbuf (xfs_buf_t *); #endif extern void libxfs_readbuf_verify(struct xfs_buf *bp, const struct xfs_buf_ops *ops); extern xfs_buf_t *libxfs_getsb(struct xfs_mount *, int); extern void libxfs_bcache_purge(void); extern void libxfs_bcache_flush(void); extern void libxfs_purgebuf(xfs_buf_t *); extern int libxfs_bcache_overflowed(void); extern int libxfs_bcache_usage(void); /* Buffer (Raw) Interfaces */ extern xfs_buf_t *libxfs_getbufr(struct xfs_buftarg *, xfs_daddr_t, int); extern void libxfs_putbufr(xfs_buf_t *); extern int libxfs_writebuf_int(xfs_buf_t *, int); extern int libxfs_writebufr(struct xfs_buf *); extern int libxfs_readbufr(struct xfs_buftarg *, xfs_daddr_t, xfs_buf_t *, int, int); extern int libxfs_readbufr_map(struct xfs_buftarg *, struct xfs_buf *, int); extern int libxfs_bhash_size; #define LIBXFS_BREAD 0x1 #define LIBXFS_BWRITE 0x2 #define LIBXFS_BZERO 0x4 extern void libxfs_iomove (xfs_buf_t *, uint, int, void *, int); static inline int xfs_buf_verify_cksum(struct xfs_buf *bp, unsigned long cksum_offset) { return xfs_verify_cksum(bp->b_addr, BBTOB(bp->b_length), cksum_offset); } static inline void xfs_buf_update_cksum(struct xfs_buf *bp, unsigned long cksum_offset) { xfs_update_cksum(bp->b_addr, BBTOB(bp->b_length), cksum_offset); } #endif /* __LIBXFS_IO_H__ */ partclone-0.2.86/src/xfs/libxfs_priv.h000066400000000000000000000373771262102574200177070ustar00rootroot00000000000000/* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ /* * This header is effectively a "namespace multiplexor" for the * user level XFS code. It provides all of the necessary stuff * such that we can build some parts of the XFS kernel code in * user space in a controlled fashion, and translates the names * used in the kernel into the names which libxfs is going to * make available to user tools. * * It should only ever be #include'd by XFS "kernel" code being * compiled in user space. * * Our goals here are to... * o "share" large amounts of complex code between user and * kernel space; * o shield the user tools from changes in the bleeding * edge kernel code, merging source changes when * convenient and not immediately (no symlinks); * o i.e. be able to merge changes to the kernel source back * into the affected user tools in a controlled fashion; * o provide a _minimalist_ life-support system for kernel * code in user land, not the "everything + the kitchen * sink" model which libsim had mutated into; * o allow the kernel code to be completely free of code * specifically there to support the user level build. */ /* * define a guard and something we can check to determine what include context * we are running from. */ #ifndef __LIBXFS_INTERNAL_XFS_H__ #define __LIBXFS_INTERNAL_XFS_H__ /* * Repair doesn't have a inode when it calls libxfs_dir2_data_freescan, * so we to work around this internally for now. */ #define xfs_dir2_data_freescan(ip, hdr, loghead) \ __xfs_dir2_data_freescan((ip)->i_mount->m_dir_geo, \ (ip)->d_ops, hdr, loghead) #include "libxfs_api_defs.h" #include "platform_defs.h" #include "xfs.h" #include "list.h" #include "hlist.h" #include "cache.h" #include "bitops.h" #include "kmem.h" #include "radix-tree.h" #include "atomic.h" #include "xfs_types.h" #include "xfs_arch.h" #include "xfs_fs.h" /* CRC stuff, buffer API dependent on it */ extern uint32_t crc32_le(uint32_t crc, unsigned char const *p, size_t len); extern uint32_t crc32c_le(uint32_t crc, unsigned char const *p, size_t len); #define crc32(c,p,l) crc32_le((c),(unsigned char const *)(p),(l)) #define crc32c(c,p,l) crc32c_le((c),(unsigned char const *)(p),(l)) #include "xfs_cksum.h" /* * This mirrors the kernel include for xfs_buf.h - it's implicitly included in * every files via a similar include in the kernel xfs_linux.h. */ #include "libxfs_io.h" /* for all the support code that uses progname in error messages */ extern char *progname; #undef ASSERT #define ASSERT(ex) assert(ex) #ifndef EWRONGFS #define EWRONGFS EINVAL #endif #define xfs_error_level 0 #define STATIC static /* XXX: need to push these out to make LIBXFS_ATTR defines */ #define ATTR_ROOT 0x0002 #define ATTR_SECURE 0x0008 #define ATTR_CREATE 0x0010 #define ATTR_REPLACE 0x0020 #define ATTR_KERNOTIME 0 #define ATTR_KERNOVAL 0 #define IHOLD(ip) ((void) 0) #define XFS_IGET_CREATE 0x1 #define XFS_IGET_UNTRUSTED 0x2 extern void cmn_err(int, char *, ...); enum ce { CE_DEBUG, CE_CONT, CE_NOTE, CE_WARN, CE_ALERT, CE_PANIC }; #define xfs_notice(mp,fmt,args...) cmn_err(CE_NOTE,fmt, ## args) #define xfs_warn(mp,fmt,args...) cmn_err(CE_WARN,fmt, ## args) #define xfs_hex_dump(d,n) ((void) 0) #define xfs_force_shutdown(d,n) ((void) 0) /* stop unused var warnings by assigning mp to itself */ #define XFS_CORRUPTION_ERROR(e,l,mp,m) do { \ (mp) = (mp); \ cmn_err(CE_ALERT, "%s: XFS_CORRUPTION_ERROR", (e)); \ } while (0) #define XFS_ERROR_REPORT(e,l,mp) do { \ (mp) = (mp); \ cmn_err(CE_ALERT, "%s: XFS_ERROR_REPORT", (e)); \ } while (0) #define XFS_QM_DQATTACH(mp,ip,flags) 0 #define XFS_ERRLEVEL_LOW 1 #define XFS_FORCED_SHUTDOWN(mp) 0 #define XFS_ILOCK_EXCL 0 #define XFS_STATS_INC(count) do { } while (0) #define XFS_STATS_DEC(count, x) do { } while (0) #define XFS_STATS_ADD(count, x) do { } while (0) #define XFS_TRANS_MOD_DQUOT_BYINO(mp,tp,ip,field,delta) do { } while (0) #define XFS_TRANS_RESERVE_QUOTA_NBLKS(mp,tp,ip,nblks,ninos,fl) 0 #define XFS_TRANS_UNRESERVE_QUOTA_NBLKS(mp,tp,ip,nblks,ninos,fl) 0 #define XFS_TEST_ERROR(expr,a,b,c) ( expr ) #define XFS_WANT_CORRUPTED_GOTO(mp, expr, l) \ { (mp) = (mp); if (!(expr)) { error = -EFSCORRUPTED; goto l; } } #define XFS_WANT_CORRUPTED_RETURN(mp, expr) \ { (mp) = (mp); if (!(expr)) { return -EFSCORRUPTED; } } #ifdef __GNUC__ #define __return_address __builtin_return_address(0) #endif #define XFS_DQUOT_CLUSTER_SIZE_FSB (xfs_filblks_t)1 /* miscellaneous kernel routines not in user space */ #define down_read(a) ((void) 0) #define up_read(a) ((void) 0) #define spin_lock_init(a) ((void) 0) #define spin_lock(a) ((void) 0) #define spin_unlock(a) ((void) 0) #define likely(x) (x) #define unlikely(x) (x) #define rcu_read_lock() ((void) 0) #define rcu_read_unlock() ((void) 0) #define WARN_ON_ONCE(expr) ((void) 0) #define percpu_counter_read(x) (*x) #define percpu_counter_read_positive(x) ((*x) > 0 ? (*x) : 0) #define percpu_counter_sum(x) (*x) /* * prandom_u32 is used for di_gen inode allocation, it must be zero for libxfs * or all sorts of badness can occur! */ #define prandom_u32() 0 #define PAGE_CACHE_SIZE getpagesize() static inline int __do_div(unsigned long long *n, unsigned base) { int __res; __res = (int)(((unsigned long) *n) % (unsigned) base); *n = ((unsigned long) *n) / (unsigned) base; return __res; } #define do_div(n,base) (__do_div((unsigned long long *)&(n), (base))) #define do_mod(a, b) ((a) % (b)) #define rol32(x,y) (((x) << (y)) | ((x) >> (32 - (y)))) #define min_t(type,x,y) \ ({ type __x = (x); type __y = (y); __x < __y ? __x: __y; }) #define max_t(type,x,y) \ ({ type __x = (x); type __y = (y); __x > __y ? __x: __y; }) #define __round_mask(x, y) ((__typeof__(x))((y)-1)) #define round_up(x, y) ((((x)-1) | __round_mask(x, y))+1) #define round_down(x, y) ((x) & ~__round_mask(x, y)) #define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d)) /* * Handling for kernel bitmap types. */ #define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, NBBY * sizeof(long)) #define DECLARE_BITMAP(name,bits) \ unsigned long name[BITS_TO_LONGS(bits)] #define BITMAP_FIRST_WORD_MASK(start) (~0UL << ((start) & (BITS_PER_LONG - 1))) /* * This is a common helper function for find_next_bit and * find_next_zero_bit. The difference is the "invert" argument, which * is XORed with each fetched word before searching it for one bits. */ static inline unsigned long _find_next_bit(const unsigned long *addr, unsigned long nbits, unsigned long start, unsigned long invert) { unsigned long tmp; if (!nbits || start >= nbits) return nbits; tmp = addr[start / BITS_PER_LONG] ^ invert; /* Handle 1st word. */ tmp &= BITMAP_FIRST_WORD_MASK(start); start = round_down(start, BITS_PER_LONG); while (!tmp) { start += BITS_PER_LONG; if (start >= nbits) return nbits; tmp = addr[start / BITS_PER_LONG] ^ invert; } return min(start + ffs(tmp), nbits); } /* * Find the next set bit in a memory region. */ static inline unsigned long find_next_bit(const unsigned long *addr, unsigned long size, unsigned long offset) { return _find_next_bit(addr, size, offset, 0UL); } static inline unsigned long find_next_zero_bit(const unsigned long *addr, unsigned long size, unsigned long offset) { return _find_next_bit(addr, size, offset, ~0UL); } #define find_first_zero_bit(addr, size) find_next_zero_bit((addr), (size), 0) static inline __attribute__((const)) int is_power_of_2(unsigned long n) { return (n != 0 && ((n & (n - 1)) == 0)); } /* * xfs_iroundup: round up argument to next power of two */ static inline uint roundup_pow_of_two(uint v) { int i; uint m; if ((v & (v - 1)) == 0) return v; ASSERT((v & 0x80000000) == 0); if ((v & (v + 1)) == 0) return v + 1; for (i = 0, m = 1; i < 31; i++, m <<= 1) { if (v & m) continue; v |= m; if ((v & (v + 1)) == 0) return v + 1; } ASSERT(0); return 0; } static inline __uint64_t roundup_64(__uint64_t x, __uint32_t y) { x += y - 1; do_div(x, y); return x * y; } /* buffer management */ #define XFS_BUF_LOCK 0 #define XFS_BUF_TRYLOCK 0 #define XBF_LOCK XFS_BUF_LOCK #define XBF_TRYLOCK XFS_BUF_TRYLOCK #define XBF_DONT_BLOCK 0 #define XBF_UNMAPPED 0 #define XBF_DONE 0 #define XFS_BUF_GETERROR(bp) 0 #define XFS_BUF_DONE(bp) ((bp)->b_flags |= LIBXFS_B_UPTODATE) #define XFS_BUF_ISDONE(bp) ((bp)->b_flags & LIBXFS_B_UPTODATE) #define xfs_buf_stale(bp) ((bp)->b_flags |= LIBXFS_B_STALE) #define XFS_BUF_UNDELAYWRITE(bp) ((bp)->b_flags &= ~LIBXFS_B_DIRTY) #define XFS_BUF_SET_VTYPE(a,b) ((void) 0) #define XFS_BUF_SET_VTYPE_REF(a,b,c) ((void) 0) #define XFS_BUF_SET_BDSTRAT_FUNC(a,b) ((void) 0) /* avoid gcc warning */ #define xfs_incore(bt,blkno,len,lockit) ({ \ typeof(blkno) __foo = (blkno); \ typeof(len) __bar = (len); \ (blkno) = __foo; \ (len) = __bar; /* no set-but-unused warning */ \ NULL; \ }) #define xfs_buf_relse(bp) libxfs_putbuf(bp) #define xfs_buf_get(devp,blkno,len,f) (libxfs_getbuf((devp), (blkno), (len))) #define xfs_bwrite(bp) libxfs_writebuf((bp), 0) #define xfs_buf_delwri_queue(bp, bl) libxfs_writebuf((bp), 0) #define XBRW_READ LIBXFS_BREAD #define XBRW_WRITE LIBXFS_BWRITE #define xfs_buf_iomove(bp,off,len,data,f) libxfs_iomove(bp,off,len,data,f) #define xfs_buf_zero(bp,off,len) libxfs_iomove(bp,off,len,0,LIBXFS_BZERO) /* mount stuff */ #define XFS_MOUNT_32BITINODES LIBXFS_MOUNT_32BITINODES #define XFS_MOUNT_ATTR2 LIBXFS_MOUNT_ATTR2 #define XFS_MOUNT_SMALL_INUMS 0 /* ignored in userspace */ #define XFS_MOUNT_WSYNC 0 /* ignored in userspace */ #define XFS_MOUNT_NOALIGN 0 /* ignored in userspace */ #define XFS_MOUNT_IKEEP 0 /* ignored in userspace */ #define XFS_MOUNT_SWALLOC 0 /* ignored in userspace */ #define XFS_MOUNT_RDONLY 0 /* ignored in userspace */ #define _xfs_trans_alloc(mp, type, f) libxfs_trans_alloc(mp, type) #define xfs_trans_get_block_res(tp) 1 #define xfs_trans_set_sync(tp) ((void) 0) #define xfs_trans_ordered_buf(tp, bp) ((void) 0) #define xfs_trans_agblocks_delta(tp, d) #define xfs_trans_agflist_delta(tp, d) #define xfs_trans_agbtree_delta(tp, d) #define xfs_trans_buf_set_type(tp, bp, t) ({ \ int __t = (t); \ __t = __t; /* no set-but-unused warning */ \ }) #define xfs_trans_buf_copy_type(dbp, sbp) /* no readahead, need to avoid set-but-unused var warnings. */ #define xfs_buf_readahead(a,d,c,ops) ({ \ xfs_daddr_t __d = d; \ __d = __d; /* no set-but-unused warning */ \ }) #define xfs_buf_readahead_map(a,b,c,ops) ((void) 0) /* no readahead */ #define xfs_buftrace(x,y) ((void) 0) /* debug only */ #define xfs_cmn_err(tag,level,mp,fmt,args...) cmn_err(level,fmt, ## args) #define xfs_warn(mp,fmt,args...) cmn_err(CE_WARN,fmt, ## args) #define xfs_alert(mp,fmt,args...) cmn_err(CE_ALERT,fmt, ## args) #define xfs_alert_tag(mp,tag,fmt,args...) cmn_err(CE_ALERT,fmt, ## args) #define xfs_dir2_trace_args(where, args) ((void) 0) #define xfs_dir2_trace_args_b(where, args, bp) ((void) 0) #define xfs_dir2_trace_args_bb(where, args, lbp, dbp) ((void) 0) #define xfs_dir2_trace_args_bibii(where, args, bs, ss, bd, sd, c) ((void) 0) #define xfs_dir2_trace_args_db(where, args, db, bp) ((void) 0) #define xfs_dir2_trace_args_i(where, args, i) ((void) 0) #define xfs_dir2_trace_args_s(where, args, s) ((void) 0) #define xfs_dir2_trace_args_sb(where, args, s, bp) ((void) 0) #define xfs_sort qsort #define xfs_icsb_reinit_counters(mp) do { } while (0) #define xfs_initialize_perag_icache(pag) ((void) 0) #define xfs_ilock(ip,mode) ((void) 0) #define xfs_ilock_nowait(ip,mode) ((void) 0) #define xfs_ilock_demote(ip,mode) ((void) 0) #define xfs_ilock_data_map_shared(ip) (0) #define xfs_ilock_attr_map_shared(ip) (0) #define xfs_iunlock(ip,mode) ({ \ typeof(mode) __mode = mode; \ __mode = __mode; /* no set-but-unused warning */ \ }) #define __xfs_flock(ip) ((void) 0) /* space allocation */ #define xfs_extent_busy_reuse(mp,ag,bno,len,user) ((void) 0) /* avoid unused variable warning */ #define xfs_extent_busy_insert(tp,ag,bno,len,flags)({ \ xfs_agnumber_t __foo = ag; \ __foo = __foo; /* no set-but-unused warning */ \ }) #define xfs_extent_busy_trim(args,fbno,flen,bno,len) \ do { \ *(bno) = (fbno); \ *(len) = (flen); \ } while (0) /* avoid unused variable warning */ #define xfs_alloc_busy_insert(tp,ag,b,len) ({ \ xfs_agnumber_t __foo = ag; \ __foo = 0; \ }) #define xfs_rotorstep 1 #define xfs_bmap_rtalloc(a) (-ENOSYS) #define xfs_get_extsz_hint(ip) (0) #define xfs_inode_is_filestream(ip) (0) #define xfs_filestream_lookup_ag(ip) (0) #define xfs_filestream_new_ag(ip,ag) (0) #define xfs_log_force(mp,flags) ((void) 0) #define XFS_LOG_SYNC 1 /* quota bits */ #define xfs_trans_mod_dquot_byino(t,i,f,d) ((void) 0) #define xfs_trans_reserve_quota_nblks(t,i,b,n,f) (0) #define xfs_trans_unreserve_quota_nblks(t,i,b,n,f) ((void) 0) #define xfs_qm_dqattach(i,f) (0) #define uuid_copy(s,d) platform_uuid_copy((s),(d)) #define uuid_equal(s,d) (platform_uuid_compare((s),(d)) == 0) #define xfs_icreate_log(tp, agno, agbno, cnt, isize, len, gen) ((void) 0) #define xfs_sb_validate_fsb_count(sbp, nblks) (0) /* * Prototypes for kernel static functions that are aren't in their * associated header files. */ struct xfs_da_args; struct xfs_bmap_free; struct xfs_bmap_free_item; struct xfs_mount; struct xfs_sb; struct xfs_trans; struct xfs_inode; struct xfs_log_item; struct xfs_buf; struct xfs_buf_map; struct xfs_buf_log_item; struct xfs_buftarg; /* xfs_attr.c */ int xfs_attr_rmtval_get(struct xfs_da_args *); /* xfs_bmap.c */ void xfs_bmap_del_free(struct xfs_bmap_free *, struct xfs_bmap_free_item *, struct xfs_bmap_free_item *); /* xfs_mount.c */ int xfs_initialize_perag_data(struct xfs_mount *, xfs_agnumber_t); void xfs_mount_common(struct xfs_mount *, struct xfs_sb *); /* * logitem.c and trans.c prototypes */ void xfs_trans_init(struct xfs_mount *); int xfs_trans_roll(struct xfs_trans **, struct xfs_inode *); /* xfs_trans_item.c */ void xfs_trans_add_item(struct xfs_trans *, struct xfs_log_item *); void xfs_trans_del_item(struct xfs_log_item *); /* xfs_inode_item.c */ void xfs_inode_item_init(struct xfs_inode *, struct xfs_mount *); /* xfs_buf_item.c */ void xfs_buf_item_init(struct xfs_buf *, struct xfs_mount *); void xfs_buf_item_log(struct xfs_buf_log_item *, uint, uint); /* xfs_trans_buf.c */ struct xfs_buf *xfs_trans_buf_item_match(struct xfs_trans *, struct xfs_buftarg *, struct xfs_buf_map *, int); /* local source files */ #define xfs_mod_fdblocks(mp, delta, rsvd) \ libxfs_mod_incore_sb(mp, XFS_TRANS_SB_FDBLOCKS, delta, rsvd) #define xfs_mod_frextents(mp, delta) \ libxfs_mod_incore_sb(mp, XFS_TRANS_SB_FREXTENTS, delta, 0) int libxfs_mod_incore_sb(struct xfs_mount *, int, int64_t, int); /* percpu counters in mp are #defined to the superblock sb_ counters */ #define xfs_reinit_percpu_counters(mp) void xfs_trans_mod_sb(struct xfs_trans *, uint, long); void xfs_trans_init(struct xfs_mount *); int xfs_trans_roll(struct xfs_trans **, struct xfs_inode *); void xfs_verifier_error(struct xfs_buf *bp); /* XXX: this is clearly a bug - a shared header needs to export this */ /* xfs_rtalloc.c */ int libxfs_rtfree_extent(struct xfs_trans *, xfs_rtblock_t, xfs_extlen_t); #endif /* __LIBXFS_INTERNAL_XFS_H__ */ partclone-0.2.86/src/xfs/libxlog.h000066400000000000000000000112351262102574200170010ustar00rootroot00000000000000/* * Copyright (c) 2000-2005 Silicon Graphics, Inc.All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef LIBXLOG_H #define LIBXLOG_H /* * define the userlevel xlog_t to be the subset of the kernel's * xlog_t that we actually need to get our work done, avoiding * the need to define any exotic kernel types in userland. */ struct xlog { xfs_lsn_t l_tail_lsn; /* lsn of 1st LR w/ unflush buffers */ xfs_lsn_t l_last_sync_lsn;/* lsn of last LR on disk */ xfs_mount_t *l_mp; /* mount point */ struct xfs_buftarg *l_dev; /* dev_t of log */ xfs_daddr_t l_logBBstart; /* start block of log */ int l_logBBsize; /* size of log in 512 byte chunks */ int l_curr_cycle; /* Cycle number of log writes */ int l_prev_cycle; /* Cycle # b4 last block increment */ int l_curr_block; /* current logical block of log */ int l_prev_block; /* previous logical block of log */ int l_iclog_size; /* size of log in bytes */ int l_iclog_size_log;/* log power size of log */ int l_iclog_bufs; /* number of iclog buffers */ atomic64_t l_grant_reserve_head; atomic64_t l_grant_write_head; uint l_sectbb_log; /* log2 of sector size in bbs */ uint l_sectbb_mask; /* sector size (in BBs) * alignment mask */ int l_sectBBsize; /* size of log sector in 512 byte chunks */ }; #include "xfs_log_recover.h" /* * macros mapping kernel code to user code * * XXX: this is duplicated stuff - should be shared with libxfs. */ #ifndef EFSCORRUPTED #define EFSCORRUPTED 990 #endif #define STATIC static #define XFS_ERROR(e) (e) #ifdef DEBUG #define XFS_ERROR_REPORT(e,l,mp) fprintf(stderr, "ERROR: %s\n", e) #else #define XFS_ERROR_REPORT(e,l,mp) ((void) 0) #endif #define XFS_CORRUPTION_ERROR(e,l,mp,m) ((void) 0) #define XFS_MOUNT_WAS_CLEAN 0x1 #define unlikely(x) (x) #define xfs_alert(mp,fmt,args...) cmn_err(CE_ALERT,fmt, ## args) #define xfs_warn(mp,fmt,args...) cmn_err(CE_WARN,fmt, ## args) #define xfs_hex_dump(d,n) ((void) 0) #define __round_mask(x, y) ((__typeof__(x))((y)-1)) #define round_up(x, y) ((((x)-1) | __round_mask(x, y))+1) #define round_down(x, y) ((x) & ~__round_mask(x, y)) extern void xlog_warn(char *fmt,...); extern void xlog_exit(char *fmt,...); extern void xlog_panic(char *fmt,...); /* exports */ extern int print_exit; extern int print_skip_uuid; extern int print_record_header; /* libxfs parameters */ extern libxfs_init_t x; extern int xlog_is_dirty(xfs_mount_t *mp, libxfs_init_t *x, int verbose); extern struct xfs_buf *xlog_get_bp(struct xlog *, int); extern void xlog_put_bp(struct xfs_buf *); extern int xlog_bread(struct xlog *log, xfs_daddr_t blk_no, int nbblks, xfs_buf_t *bp, char **offset); extern int xlog_bread_noalign(struct xlog *log, xfs_daddr_t blk_no, int nbblks, xfs_buf_t *bp); extern int xlog_find_zeroed(struct xlog *log, xfs_daddr_t *blk_no); extern int xlog_find_cycle_start(struct xlog *log, xfs_buf_t *bp, xfs_daddr_t first_blk, xfs_daddr_t *last_blk, uint cycle); extern int xlog_find_tail(struct xlog *log, xfs_daddr_t *head_blk, xfs_daddr_t *tail_blk); extern int xlog_test_footer(struct xlog *log); extern int xlog_recover(struct xlog *log, int readonly); extern void xlog_recover_print_data(char *p, int len); extern void xlog_recover_print_logitem(xlog_recover_item_t *item); extern void xlog_recover_print_trans_head(xlog_recover_t *tr); extern int xlog_print_find_oldest(struct xlog *log, xfs_daddr_t *last_blk); /* for transactional view */ extern void xlog_recover_print_trans_head(xlog_recover_t *tr); extern void xlog_recover_print_trans(xlog_recover_t *trans, struct list_head *itemq, int print); extern int xlog_do_recovery_pass(struct xlog *log, xfs_daddr_t head_blk, xfs_daddr_t tail_blk, int pass); extern int xlog_recover_do_trans(struct xlog *log, xlog_recover_t *trans, int pass); extern int xlog_header_check_recover(xfs_mount_t *mp, xlog_rec_header_t *head); extern int xlog_header_check_mount(xfs_mount_t *mp, xlog_rec_header_t *head); #define xlog_assign_atomic_lsn(l,a,b) ((void) 0) #define xlog_assign_grant_head(l,a,b) ((void) 0) #endif /* LIBXLOG_H */ partclone-0.2.86/src/xfs/linux.c000066400000000000000000000120571262102574200164760ustar00rootroot00000000000000/* * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #define ustat __kernel_ustat #include #include #undef ustat #include #include #include #include #include "libxfs_priv.h" #include "xfs_fs.h" int platform_has_uuid = 1; extern char *progname; static int max_block_alignment; #ifndef BLKGETSIZE64 # define BLKGETSIZE64 _IOR(0x12,114,size_t) #endif #ifndef BLKBSZSET # define BLKBSZSET _IOW(0x12,113,size_t) #endif #ifndef BLKSSZGET # define BLKSSZGET _IO(0x12,104) #endif #ifndef RAMDISK_MAJOR #define RAMDISK_MAJOR 1 /* ramdisk major number */ #endif #define PROC_MOUNTED "/proc/mounts" int platform_check_ismounted(char *name, char *block, struct stat64 *s, int verbose) { /* Pad ust; pre-2.6.28 linux copies out too much in 32bit compat mode */ struct ustat ust[2]; struct stat64 st; if (!s) { if (stat64(block, &st) < 0) return 0; if ((st.st_mode & S_IFMT) != S_IFBLK) return 0; s = &st; } if (ustat(s->st_rdev, ust) >= 0) { if (verbose) fprintf(stderr, _("%s: %s contains a mounted filesystem\n"), progname, name); return 1; } return 0; } int platform_check_iswritable(char *name, char *block, struct stat64 *s, int fatal) { int sts = 0; FILE *f; struct stat64 mst; struct mntent *mnt; char mounts[MAXPATHLEN]; strcpy(mounts, (!access(PROC_MOUNTED, R_OK)) ? PROC_MOUNTED : MOUNTED); if ((f = setmntent(mounts, "r")) == NULL) { fprintf(stderr, _("%s: %s contains a possibly writable, " "mounted filesystem\n"), progname, name); return fatal; } while ((mnt = getmntent(f)) != NULL) { if (stat64(mnt->mnt_fsname, &mst) < 0) continue; if ((mst.st_mode & S_IFMT) != S_IFBLK) continue; if (mst.st_rdev == s->st_rdev && hasmntopt(mnt, MNTOPT_RO) != NULL) break; } if (mnt == NULL) { fprintf(stderr, _("%s: %s contains a mounted and writable " "filesystem\n"), progname, name); sts = fatal; } endmntent(f); return sts; } int platform_set_blocksize(int fd, char *path, dev_t device, int blocksize, int fatal) { int error = 0; if (major(device) != RAMDISK_MAJOR) { if ((error = ioctl(fd, BLKBSZSET, &blocksize)) < 0) { fprintf(stderr, _("%s: %s - cannot set blocksize " "%d on block device %s: %s\n"), progname, fatal ? "error": "warning", blocksize, path, strerror(errno)); } } return error; } void platform_flush_device(int fd, dev_t device) { if (major(device) != RAMDISK_MAJOR) ioctl(fd, BLKFLSBUF, 0); } void platform_findsizes(char *path, int fd, long long *sz, int *bsz) { struct stat64 st; __uint64_t size; int error; if (fstat64(fd, &st) < 0) { fprintf(stderr, _("%s: " "cannot stat the device file \"%s\": %s\n"), progname, path, strerror(errno)); exit(1); } if ((st.st_mode & S_IFMT) == S_IFREG) { struct xfs_fsop_geom_v1 geom = { 0 }; *sz = (long long)(st.st_size >> 9); if (ioctl(fd, XFS_IOC_FSGEOMETRY_V1, &geom) < 0) { /* * fall back to BBSIZE; mkfs might fail if there's a * size mismatch between the image & the host fs... */ *bsz = BBSIZE; } else *bsz = geom.sectsize; if (*bsz > max_block_alignment) max_block_alignment = *bsz; return; } error = ioctl(fd, BLKGETSIZE64, &size); if (error >= 0) { /* BLKGETSIZE64 returns size in bytes not 512-byte blocks */ *sz = (long long)(size >> 9); } else { /* If BLKGETSIZE64 fails, try BLKGETSIZE */ unsigned long tmpsize; error = ioctl(fd, BLKGETSIZE, &tmpsize); if (error < 0) { fprintf(stderr, _("%s: can't determine device size\n"), progname); exit(1); } *sz = (long long)tmpsize; } if (ioctl(fd, BLKSSZGET, bsz) < 0) { fprintf(stderr, _("%s: warning - cannot get sector size " "from block device %s: %s\n"), progname, path, strerror(errno)); *bsz = BBSIZE; } if (*bsz > max_block_alignment) max_block_alignment = *bsz; } char * platform_findrawpath(char *path) { return path; } char * platform_findblockpath(char *path) { return path; } int platform_direct_blockdev(void) { return 1; } int platform_align_blockdev(void) { if (!max_block_alignment) return getpagesize(); return max_block_alignment; } int platform_nproc(void) { return sysconf(_SC_NPROCESSORS_ONLN); } unsigned long platform_physmem(void) { struct sysinfo si; if (sysinfo(&si) < 0) { fprintf(stderr, _("%s: can't determine memory size\n"), progname); exit(1); } return (si.totalram >> 10) * si.mem_unit; /* kilobytes */ } partclone-0.2.86/src/xfs/linux.h000066400000000000000000000067551262102574200165130ustar00rootroot00000000000000/* * Copyright (c) 2004-2005 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __XFS_LINUX_H__ #define __XFS_LINUX_H__ #include #include #include #include #include #include #include #include #include #include #include #include #include static __inline__ int xfsctl(const char *path, int fd, int cmd, void *p) { return ioctl(fd, cmd, p); } /* * platform_test_xfs_*() implies that xfsctl will succeed on the file; * on Linux, at least, special files don't get xfs file ops, * so return 0 for those */ static __inline__ int platform_test_xfs_fd(int fd) { struct statfs statfsbuf; struct stat statbuf; if (fstatfs(fd, &statfsbuf) < 0) return 0; if (fstat(fd, &statbuf) < 0) return 0; if (!S_ISREG(statbuf.st_mode) && !S_ISDIR(statbuf.st_mode)) return 0; return (statfsbuf.f_type == 0x58465342); /* XFSB */ } static __inline__ int platform_test_xfs_path(const char *path) { struct statfs statfsbuf; struct stat statbuf; if (statfs(path, &statfsbuf) < 0) return 0; if (stat(path, &statbuf) < 0) return 0; if (!S_ISREG(statbuf.st_mode) && !S_ISDIR(statbuf.st_mode)) return 0; return (statfsbuf.f_type == 0x58465342); /* XFSB */ } static __inline__ int platform_fstatfs(int fd, struct statfs *buf) { return fstatfs(fd, buf); } static __inline__ void platform_getoptreset(void) { extern int optind; optind = 0; } static __inline__ int platform_uuid_compare(uuid_t *uu1, uuid_t *uu2) { return uuid_compare(*uu1, *uu2); } static __inline__ void platform_uuid_unparse(uuid_t *uu, char *buffer) { uuid_unparse(*uu, buffer); } static __inline__ int platform_uuid_parse(char *buffer, uuid_t *uu) { return uuid_parse(buffer, *uu); } static __inline__ int platform_uuid_is_null(uuid_t *uu) { return uuid_is_null(*uu); } static __inline__ void platform_uuid_generate(uuid_t *uu) { uuid_generate(*uu); } static __inline__ void platform_uuid_clear(uuid_t *uu) { uuid_clear(*uu); } static __inline__ void platform_uuid_copy(uuid_t *dst, uuid_t *src) { uuid_copy(*dst, *src); } #ifndef BLKDISCARD #define BLKDISCARD _IO(0x12,119) #endif static __inline__ int platform_discard_blocks(int fd, uint64_t start, uint64_t len) { __uint64_t range[2] = { start, len }; if (ioctl(fd, BLKDISCARD, &range) < 0) return errno; return 0; } #if (__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ <= 1)) # define constpp const char * const * #else # define constpp char * const * #endif #define ENOATTR ENODATA /* Attribute not found */ #define EFSCORRUPTED EUCLEAN /* Filesystem is corrupted */ #define EFSBADCRC EBADMSG /* Bad CRC detected */ typedef loff_t xfs_off_t; typedef __uint64_t xfs_ino_t; typedef __uint32_t xfs_dev_t; typedef __int64_t xfs_daddr_t; #endif /* __XFS_LINUX_H__ */ partclone-0.2.86/src/xfs/list.h000066400000000000000000000104151262102574200163130ustar00rootroot00000000000000/* * Copyright (c) 2006 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __LIST_H__ #define __LIST_H__ /* * This undef is here because BSD 4.4 added some LIST_ macros into system * header file sys/queue.h. This header is included in many other system * headers and thus causes "macro redefined" warnings. * * As OS X is kind of a derivate of BSD, this affects OS X too. * * To use our own LIST_ macros (copied from kernel code), we have to * at first undefine the conflicting system macros. * */ #undef LIST_HEAD #undef LIST_HEAD_INIT /* * Simple, generic doubly-linked list implementation. */ struct list_head { struct list_head *next; struct list_head *prev; }; #define LIST_HEAD_INIT(name) { &(name), &(name) } #define LIST_HEAD(name) \ struct list_head name = LIST_HEAD_INIT(name) #define INIT_LIST_HEAD(list) list_head_init(list) static inline void list_head_init(struct list_head *list) { list->next = list->prev = list; } static inline void list_head_destroy(struct list_head *list) { list->next = list->prev = NULL; } static inline void __list_add(struct list_head *add, struct list_head *prev, struct list_head *next) { next->prev = add; add->next = next; add->prev = prev; prev->next = add; } static inline void list_add(struct list_head *add, struct list_head *head) { __list_add(add, head, head->next); } static inline void list_add_tail(struct list_head *add, struct list_head *head) { __list_add(add, head->prev, head); } static inline void __list_del(struct list_head *prev, struct list_head *next) { next->prev = prev; prev->next = next; } static inline void list_del_init(struct list_head *entry) { __list_del(entry->prev, entry->next); list_head_init(entry); } static inline void list_del(struct list_head *entry) { __list_del(entry->prev, entry->next); } static inline void list_move(struct list_head *list, struct list_head *head) { __list_del(list->prev, list->next); list_add(list, head); } static inline void list_move_tail(struct list_head *list, struct list_head *head) { __list_del(list->prev, list->next); list_add_tail(list, head); } static inline int list_empty(const struct list_head *head) { return head->next == head; } static inline void __list_splice(struct list_head *list, struct list_head *head) { struct list_head *first = list->next; struct list_head *last = list->prev; struct list_head *at = head->next; first->prev = head; head->next = first; last->next = at; at->prev = last; } static inline void list_splice(struct list_head *list, struct list_head *head) { if (!list_empty(list)) __list_splice(list, head); } static inline void list_splice_init(struct list_head *list, struct list_head *head) { if (!list_empty(list)) { __list_splice(list, head); list_head_init(list); } } #define list_entry(ptr, type, member) ({ \ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ (type *)( (char *)__mptr - offsetof(type,member) );}) #define list_for_each(pos, head) \ for (pos = (head)->next; pos != (head); pos = pos->next) #define list_for_each_safe(pos, n, head) \ for (pos = (head)->next, n = pos->next; pos != (head); \ pos = n, n = pos->next) #define list_for_each_entry(pos, head, member) \ for (pos = list_entry((head)->next, typeof(*pos), member); \ &pos->member != (head); \ pos = list_entry(pos->member.next, typeof(*pos), member)) #define list_for_each_entry_safe(pos, n, head, member) \ for (pos = list_entry((head)->next, typeof(*pos), member), \ n = list_entry(pos->member.next, typeof(*pos), member); \ &pos->member != (head); \ pos = n, n = list_entry(n->member.next, typeof(*n), member)) #endif /* __LIST_H__ */ partclone-0.2.86/src/xfs/logitem.c000066400000000000000000000110361262102574200167730ustar00rootroot00000000000000/* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_mount.h" #include "xfs_inode_buf.h" #include "xfs_inode_fork.h" #include "xfs_inode.h" #include "xfs_trans.h" kmem_zone_t *xfs_buf_item_zone; kmem_zone_t *xfs_ili_zone; /* inode log item zone */ /* * Following functions from fs/xfs/xfs_trans_buf.c */ /* * Check to see if a buffer matching the given parameters is already * a part of the given transaction. */ xfs_buf_t * xfs_trans_buf_item_match( xfs_trans_t *tp, struct xfs_buftarg *btp, struct xfs_buf_map *map, int nmaps) { struct xfs_log_item_desc *lidp; struct xfs_buf_log_item *blip; int len = 0; int i; for (i = 0; i < nmaps; i++) len += map[i].bm_len; list_for_each_entry(lidp, &tp->t_items, lid_trans) { blip = (struct xfs_buf_log_item *)lidp->lid_item; if (blip->bli_item.li_type == XFS_LI_BUF && blip->bli_buf->b_target->dev == btp->dev && XFS_BUF_ADDR(blip->bli_buf) == map[0].bm_bn && blip->bli_buf->b_bcount == BBTOB(len)) { ASSERT(blip->bli_buf->b_map_count == nmaps); return blip->bli_buf; } } return NULL; } /* * The following are from fs/xfs/xfs_buf_item.c */ /* * Allocate a new buf log item to go with the given buffer. * Set the buffer's b_fsprivate field to point to the new * buf log item. If there are other item's attached to the * buffer (see xfs_buf_attach_iodone() below), then put the * buf log item at the front. */ void xfs_buf_item_init( xfs_buf_t *bp, xfs_mount_t *mp) { xfs_log_item_t *lip; xfs_buf_log_item_t *bip; #ifdef LI_DEBUG fprintf(stderr, "buf_item_init for buffer %p\n", bp); #endif /* * Check to see if there is already a buf log item for * this buffer. If there is, it is guaranteed to be * the first. If we do already have one, there is * nothing to do here so return. */ if (XFS_BUF_FSPRIVATE3(bp, xfs_mount_t *) != mp) XFS_BUF_SET_FSPRIVATE3(bp, mp); XFS_BUF_SET_BDSTRAT_FUNC(bp, xfs_bdstrat_cb); if (XFS_BUF_FSPRIVATE(bp, void *) != NULL) { lip = XFS_BUF_FSPRIVATE(bp, xfs_log_item_t *); if (lip->li_type == XFS_LI_BUF) { #ifdef LI_DEBUG fprintf(stderr, "reused buf item %p for pre-logged buffer %p\n", lip, bp); #endif return; } } bip = (xfs_buf_log_item_t *)kmem_zone_zalloc(xfs_buf_item_zone, KM_SLEEP); #ifdef LI_DEBUG fprintf(stderr, "adding buf item %p for not-logged buffer %p\n", bip, bp); #endif bip->bli_item.li_type = XFS_LI_BUF; bip->bli_item.li_mountp = mp; bip->bli_buf = bp; bip->bli_format.blf_type = XFS_LI_BUF; bip->bli_format.blf_blkno = (__int64_t)XFS_BUF_ADDR(bp); bip->bli_format.blf_len = (unsigned short)BTOBB(XFS_BUF_COUNT(bp)); XFS_BUF_SET_FSPRIVATE(bp, bip); } /* * Mark bytes first through last inclusive as dirty in the buf * item's bitmap. */ void xfs_buf_item_log( xfs_buf_log_item_t *bip, uint first, uint last) { /* * Mark the item as having some dirty data for * quick reference in xfs_buf_item_dirty. */ bip->bli_flags |= XFS_BLI_DIRTY; } /* * Initialize the inode log item for a newly allocated (in-core) inode. */ void xfs_inode_item_init( xfs_inode_t *ip, xfs_mount_t *mp) { xfs_inode_log_item_t *iip; ASSERT(ip->i_itemp == NULL); iip = ip->i_itemp = (xfs_inode_log_item_t *) kmem_zone_zalloc(xfs_ili_zone, KM_SLEEP); #ifdef LI_DEBUG fprintf(stderr, "inode_item_init for inode %llu, iip=%p\n", ip->i_ino, iip); #endif iip->ili_item.li_type = XFS_LI_INODE; iip->ili_item.li_mountp = mp; iip->ili_inode = ip; iip->ili_format.ilf_type = XFS_LI_INODE; iip->ili_format.ilf_ino = ip->i_ino; iip->ili_format.ilf_blkno = ip->i_imap.im_blkno; iip->ili_format.ilf_len = ip->i_imap.im_len; iip->ili_format.ilf_boffset = ip->i_imap.im_boffset; } partclone-0.2.86/src/xfs/parent.h000066400000000000000000000017301262102574200166310ustar00rootroot00000000000000/* * Copyright (c) 2005 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __PARENT_H__ #define __PARENT_H__ typedef struct parent { __u64 p_ino; __u32 p_gen; __u16 p_reclen; char p_name[1]; } parent_t; typedef struct parent_cursor { __u32 opaque[4]; /* an opaque cookie */ } parent_cursor_t; #endif partclone-0.2.86/src/xfs/path.h000066400000000000000000000043711262102574200163000ustar00rootroot00000000000000/* * Copyright (c) 2005 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __PATH_H__ #define __PATH_H__ #include "platform_defs.h" /* * XFS Filesystem Paths * * Utility routines for iterating and searching through the list * of known mounted filesystems and project paths. */ #define FS_MOUNT_POINT (1<<0) #define FS_PROJECT_PATH (1<<1) typedef struct fs_path { char *fs_name; /* Data device for filesystem */ dev_t fs_datadev; char *fs_log; /* External log device, if any */ dev_t fs_logdev; char *fs_rt; /* Realtime device, if any */ dev_t fs_rtdev; char *fs_dir; /* Directory / mount point */ uint fs_flags; /* FS_{MOUNT_POINT,PROJECT_PATH}*/ uint fs_prid; /* Project ID for tree root */ } fs_path_t; extern int fs_count; /* number of entries in fs table */ extern fs_path_t *fs_table; /* array of entries in fs table */ extern fs_path_t *fs_path; /* current entry in the fs table */ extern char *mtab_file; extern void fs_table_initialise(int, char *[], int, char *[]); extern void fs_table_destroy(void); extern void fs_table_insert_project_path(char *__dir, uint __projid); extern fs_path_t *fs_table_lookup(const char *__dir, uint __flags); typedef struct fs_cursor { uint count; /* total count of mount entries */ uint index; /* current position in table */ uint flags; /* iterator flags: mounts/trees */ fs_path_t *table; /* local/global table pointer */ fs_path_t local; /* space for single-entry table */ } fs_cursor_t; extern void fs_cursor_initialise(char *__dir, uint __flags, fs_cursor_t *__cp); extern fs_path_t *fs_cursor_next_entry(fs_cursor_t *__cp); #endif /* __PATH_H__ */ partclone-0.2.86/src/xfs/platform_defs.h000066400000000000000000000050141262102574200201640ustar00rootroot00000000000000/* include/platform_defs.h. Generated from platform_defs.h.in by configure. */ /* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * @configure_input@ */ #ifndef __XFS_PLATFORM_DEFS_H__ #define __XFS_PLATFORM_DEFS_H__ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include typedef struct filldir filldir_t; /* long and pointer must be either 32 bit or 64 bit */ #define SIZEOF_LONG 4 #define SIZEOF_CHAR_P 4 #define BITS_PER_LONG (SIZEOF_LONG * CHAR_BIT) /* Check whether to define umode_t ourselves. */ #ifndef HAVE_UMODE_T typedef unsigned short umode_t; #endif /* Define if you want gettext (I18N) support */ /* #undef ENABLE_GETTEXT */ #ifdef ENABLE_GETTEXT # include # define _(x) gettext(x) # define N_(x) x #else # define _(x) (x) # define N_(x) x # define textdomain(d) do { } while (0) # define bindtextdomain(d,dir) do { } while (0) #endif #include #define IRIX_DEV_BITSMAJOR 14 #define IRIX_DEV_BITSMINOR 18 #define IRIX_DEV_MAXMAJ 0x1ff #define IRIX_DEV_MAXMIN 0x3ffff #define IRIX_DEV_MAJOR(dev) ((int)(((unsigned)(dev) >> IRIX_DEV_BITSMINOR) \ & IRIX_DEV_MAXMAJ)) #define IRIX_DEV_MINOR(dev) ((int)((dev) & IRIX_DEV_MAXMIN)) #define IRIX_MKDEV(major,minor) ((xfs_dev_t)(((major) << IRIX_DEV_BITSMINOR) \ | (minor&IRIX_DEV_MAXMIN))) #define IRIX_DEV_TO_KDEVT(dev) makedev(IRIX_DEV_MAJOR(dev),IRIX_DEV_MINOR(dev)) #ifndef min #define min(a,b) (((a)<(b))?(a):(b)) #define max(a,b) (((a)>(b))?(a):(b)) #endif #ifndef NBBY #define NBBY 8 #endif #endif /* __XFS_PLATFORM_DEFS_H__ */ partclone-0.2.86/src/xfs/platform_defs.h.in000066400000000000000000000046571262102574200206050ustar00rootroot00000000000000/* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * @configure_input@ */ #ifndef __XFS_PLATFORM_DEFS_H__ #define __XFS_PLATFORM_DEFS_H__ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include typedef struct filldir filldir_t; /* long and pointer must be either 32 bit or 64 bit */ #undef SIZEOF_LONG #undef SIZEOF_CHAR_P #define BITS_PER_LONG (SIZEOF_LONG * CHAR_BIT) /* Check whether to define umode_t ourselves. */ #ifndef HAVE_UMODE_T typedef unsigned short umode_t; #endif /* Define if you want gettext (I18N) support */ #undef ENABLE_GETTEXT #ifdef ENABLE_GETTEXT # include # define _(x) gettext(x) # define N_(x) x #else # define _(x) (x) # define N_(x) x # define textdomain(d) do { } while (0) # define bindtextdomain(d,dir) do { } while (0) #endif #include #define IRIX_DEV_BITSMAJOR 14 #define IRIX_DEV_BITSMINOR 18 #define IRIX_DEV_MAXMAJ 0x1ff #define IRIX_DEV_MAXMIN 0x3ffff #define IRIX_DEV_MAJOR(dev) ((int)(((unsigned)(dev) >> IRIX_DEV_BITSMINOR) \ & IRIX_DEV_MAXMAJ)) #define IRIX_DEV_MINOR(dev) ((int)((dev) & IRIX_DEV_MAXMIN)) #define IRIX_MKDEV(major,minor) ((xfs_dev_t)(((major) << IRIX_DEV_BITSMINOR) \ | (minor&IRIX_DEV_MAXMIN))) #define IRIX_DEV_TO_KDEVT(dev) makedev(IRIX_DEV_MAJOR(dev),IRIX_DEV_MINOR(dev)) #ifndef min #define min(a,b) (((a)<(b))?(a):(b)) #define max(a,b) (((a)>(b))?(a):(b)) #endif #ifndef NBBY #define NBBY 8 #endif #endif /* __XFS_PLATFORM_DEFS_H__ */ partclone-0.2.86/src/xfs/project.h000066400000000000000000000031341262102574200170060ustar00rootroot00000000000000/* * Copyright (c) 2005 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __PROJECT_H__ #define __PROJECT_H__ #include "platform_defs.h" #include "xfs.h" extern int setprojid(const char *__name, int __fd, prid_t __id); extern int getprojid(const char *__name, int __fd, prid_t *__id); typedef struct fs_project { prid_t pr_prid; /* project identifier */ char *pr_name; /* project name */ } fs_project_t; extern void setprent(void); extern void endprent(void); extern fs_project_t *getprent(void); extern fs_project_t *getprnam(char *__name); extern fs_project_t *getprprid(prid_t __id); typedef struct fs_project_path { prid_t pp_prid; /* project identifier */ char *pp_pathname; /* pathname to root of project tree */ } fs_project_path_t; extern void setprpathent(void); extern void endprpathent(void); extern fs_project_path_t *getprpathent(void); extern void setprfiles(void); extern char *projid_file; extern char *projects_file; #endif /* __PROJECT_H__ */ partclone-0.2.86/src/xfs/radix-tree.c000066400000000000000000000462421262102574200174060ustar00rootroot00000000000000/* * Copyright (C) 2001 Momchil Velikov * Portions Copyright (C) 2001 Christoph Hellwig * Copyright (C) 2005 SGI, Christoph Lameter * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "platform_defs.h" #include "xfs.h" #include "radix-tree.h" #ifndef ARRAY_SIZE #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) #endif #define RADIX_TREE_MAP_SHIFT 6 #define RADIX_TREE_MAP_SIZE (1UL << RADIX_TREE_MAP_SHIFT) #define RADIX_TREE_MAP_MASK (RADIX_TREE_MAP_SIZE-1) #ifdef RADIX_TREE_TAGS #define RADIX_TREE_TAG_LONGS \ ((RADIX_TREE_MAP_SIZE + BITS_PER_LONG - 1) / BITS_PER_LONG) #endif struct radix_tree_node { unsigned int count; void *slots[RADIX_TREE_MAP_SIZE]; #ifdef RADIX_TREE_TAGS unsigned long tags[RADIX_TREE_MAX_TAGS][RADIX_TREE_TAG_LONGS]; #endif }; struct radix_tree_path { struct radix_tree_node *node; int offset; }; #define RADIX_TREE_INDEX_BITS (8 /* CHAR_BIT */ * sizeof(unsigned long)) #define RADIX_TREE_MAX_PATH (RADIX_TREE_INDEX_BITS/RADIX_TREE_MAP_SHIFT + 2) static unsigned long height_to_maxindex[RADIX_TREE_MAX_PATH]; /* * Radix tree node cache. */ #define radix_tree_node_alloc(r) ((struct radix_tree_node *) \ calloc(1, sizeof(struct radix_tree_node))) #define radix_tree_node_free(n) free(n) #ifdef RADIX_TREE_TAGS static inline void tag_set(struct radix_tree_node *node, unsigned int tag, int offset) { *((__uint32_t *)node->tags[tag] + (offset >> 5)) |= (1 << (offset & 31)); } static inline void tag_clear(struct radix_tree_node *node, unsigned int tag, int offset) { __uint32_t *p = (__uint32_t*)node->tags[tag] + (offset >> 5); __uint32_t m = 1 << (offset & 31); *p &= ~m; } static inline int tag_get(struct radix_tree_node *node, unsigned int tag, int offset) { return 1 & (((const __uint32_t *)node->tags[tag])[offset >> 5] >> (offset & 31)); } /* * Returns 1 if any slot in the node has this tag set. * Otherwise returns 0. */ static inline int any_tag_set(struct radix_tree_node *node, unsigned int tag) { int idx; for (idx = 0; idx < RADIX_TREE_TAG_LONGS; idx++) { if (node->tags[tag][idx]) return 1; } return 0; } #endif /* * Return the maximum key which can be store into a * radix tree with height HEIGHT. */ static inline unsigned long radix_tree_maxindex(unsigned int height) { return height_to_maxindex[height]; } /* * Extend a radix tree so it can store key @index. */ static int radix_tree_extend(struct radix_tree_root *root, unsigned long index) { struct radix_tree_node *node; unsigned int height; #ifdef RADIX_TREE_TAGS char tags[RADIX_TREE_MAX_TAGS]; int tag; #endif /* Figure out what the height should be. */ height = root->height + 1; while (index > radix_tree_maxindex(height)) height++; if (root->rnode == NULL) { root->height = height; goto out; } #ifdef RADIX_TREE_TAGS /* * Prepare the tag status of the top-level node for propagation * into the newly-pushed top-level node(s) */ for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++) { tags[tag] = 0; if (any_tag_set(root->rnode, tag)) tags[tag] = 1; } #endif do { if (!(node = radix_tree_node_alloc(root))) return -ENOMEM; /* Increase the height. */ node->slots[0] = root->rnode; #ifdef RADIX_TREE_TAGS /* Propagate the aggregated tag info into the new root */ for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++) { if (tags[tag]) tag_set(node, tag, 0); } #endif node->count = 1; root->rnode = node; root->height++; } while (height > root->height); out: return 0; } /** * radix_tree_insert - insert into a radix tree * @root: radix tree root * @index: index key * @item: item to insert * * Insert an item into the radix tree at position @index. */ int radix_tree_insert(struct radix_tree_root *root, unsigned long index, void *item) { struct radix_tree_node *node = NULL, *slot; unsigned int height, shift; int offset; int error; /* Make sure the tree is high enough. */ if ((!index && !root->rnode) || index > radix_tree_maxindex(root->height)) { error = radix_tree_extend(root, index); if (error) return error; } slot = root->rnode; height = root->height; shift = (height-1) * RADIX_TREE_MAP_SHIFT; offset = 0; /* uninitialised var warning */ do { if (slot == NULL) { /* Have to add a child node. */ if (!(slot = radix_tree_node_alloc(root))) return -ENOMEM; if (node) { node->slots[offset] = slot; node->count++; } else root->rnode = slot; } /* Go a level down */ offset = (index >> shift) & RADIX_TREE_MAP_MASK; node = slot; slot = node->slots[offset]; shift -= RADIX_TREE_MAP_SHIFT; height--; } while (height > 0); if (slot != NULL) return -EEXIST; ASSERT(node); node->count++; node->slots[offset] = item; #ifdef RADIX_TREE_TAGS ASSERT(!tag_get(node, 0, offset)); ASSERT(!tag_get(node, 1, offset)); #endif return 0; } static inline void **__lookup_slot(struct radix_tree_root *root, unsigned long index) { unsigned int height, shift; struct radix_tree_node **slot; height = root->height; if (index > radix_tree_maxindex(height)) return NULL; shift = (height-1) * RADIX_TREE_MAP_SHIFT; slot = &root->rnode; while (height > 0) { if (*slot == NULL) return NULL; slot = (struct radix_tree_node **) ((*slot)->slots + ((index >> shift) & RADIX_TREE_MAP_MASK)); shift -= RADIX_TREE_MAP_SHIFT; height--; } return (void **)slot; } /** * radix_tree_lookup_slot - lookup a slot in a radix tree * @root: radix tree root * @index: index key * * Lookup the slot corresponding to the position @index in the radix tree * @root. This is useful for update-if-exists operations. */ void **radix_tree_lookup_slot(struct radix_tree_root *root, unsigned long index) { return __lookup_slot(root, index); } /** * radix_tree_lookup - perform lookup operation on a radix tree * @root: radix tree root * @index: index key * * Lookup the item at the position @index in the radix tree @root. */ void *radix_tree_lookup(struct radix_tree_root *root, unsigned long index) { void **slot; slot = __lookup_slot(root, index); return slot != NULL ? *slot : NULL; } /** * raid_tree_first_key - find the first index key in the radix tree * @root: radix tree root * @index: where the first index will be placed * * Returns the first entry and index key in the radix tree @root. */ void *radix_tree_lookup_first(struct radix_tree_root *root, unsigned long *index) { unsigned int height, shift; struct radix_tree_node *slot; unsigned long i; height = root->height; *index = 0; if (height == 0) return NULL; shift = (height-1) * RADIX_TREE_MAP_SHIFT; slot = root->rnode; for (; height > 1; height--) { for (i = 0; i < RADIX_TREE_MAP_SIZE; i++) { if (slot->slots[i] != NULL) break; } ASSERT(i < RADIX_TREE_MAP_SIZE); *index |= (i << shift); shift -= RADIX_TREE_MAP_SHIFT; slot = slot->slots[i]; } for (i = 0; i < RADIX_TREE_MAP_SIZE; i++) { if (slot->slots[i] != NULL) { *index |= i; return slot->slots[i]; } } return NULL; } #ifdef RADIX_TREE_TAGS /** * radix_tree_tag_set - set a tag on a radix tree node * @root: radix tree root * @index: index key * @tag: tag index * * Set the search tag (which must be < RADIX_TREE_MAX_TAGS) * corresponding to @index in the radix tree. From * the root all the way down to the leaf node. * * Returns the address of the tagged item. Setting a tag on a not-present * item is a bug. */ void *radix_tree_tag_set(struct radix_tree_root *root, unsigned long index, unsigned int tag) { unsigned int height, shift; struct radix_tree_node *slot; height = root->height; if (index > radix_tree_maxindex(height)) return NULL; shift = (height - 1) * RADIX_TREE_MAP_SHIFT; slot = root->rnode; while (height > 0) { int offset; offset = (index >> shift) & RADIX_TREE_MAP_MASK; if (!tag_get(slot, tag, offset)) tag_set(slot, tag, offset); slot = slot->slots[offset]; ASSERT(slot != NULL); shift -= RADIX_TREE_MAP_SHIFT; height--; } return slot; } /** * radix_tree_tag_clear - clear a tag on a radix tree node * @root: radix tree root * @index: index key * @tag: tag index * * Clear the search tag (which must be < RADIX_TREE_MAX_TAGS) * corresponding to @index in the radix tree. If * this causes the leaf node to have no tags set then clear the tag in the * next-to-leaf node, etc. * * Returns the address of the tagged item on success, else NULL. ie: * has the same return value and semantics as radix_tree_lookup(). */ void *radix_tree_tag_clear(struct radix_tree_root *root, unsigned long index, unsigned int tag) { struct radix_tree_path path[RADIX_TREE_MAX_PATH + 1], *pathp = path; struct radix_tree_node *slot; unsigned int height, shift; void *ret = NULL; height = root->height; if (index > radix_tree_maxindex(height)) goto out; shift = (height - 1) * RADIX_TREE_MAP_SHIFT; pathp->node = NULL; slot = root->rnode; while (height > 0) { int offset; if (slot == NULL) goto out; offset = (index >> shift) & RADIX_TREE_MAP_MASK; pathp[1].offset = offset; pathp[1].node = slot; slot = slot->slots[offset]; pathp++; shift -= RADIX_TREE_MAP_SHIFT; height--; } ret = slot; if (ret == NULL) goto out; do { if (!tag_get(pathp->node, tag, pathp->offset)) goto out; tag_clear(pathp->node, tag, pathp->offset); if (any_tag_set(pathp->node, tag)) goto out; pathp--; } while (pathp->node); out: return ret; } #endif static unsigned int __lookup(struct radix_tree_root *root, void **results, unsigned long index, unsigned int max_items, unsigned long *next_index) { unsigned int nr_found = 0; unsigned int shift, height; struct radix_tree_node *slot; unsigned long i; height = root->height; if (height == 0) goto out; shift = (height-1) * RADIX_TREE_MAP_SHIFT; slot = root->rnode; for ( ; height > 1; height--) { for (i = (index >> shift) & RADIX_TREE_MAP_MASK ; i < RADIX_TREE_MAP_SIZE; i++) { if (slot->slots[i] != NULL) break; index &= ~((1UL << shift) - 1); index += 1UL << shift; if (index == 0) goto out; /* 32-bit wraparound */ } if (i == RADIX_TREE_MAP_SIZE) goto out; shift -= RADIX_TREE_MAP_SHIFT; slot = slot->slots[i]; } /* Bottom level: grab some items */ for (i = index & RADIX_TREE_MAP_MASK; i < RADIX_TREE_MAP_SIZE; i++) { index++; if (slot->slots[i]) { results[nr_found++] = slot->slots[i]; if (nr_found == max_items) goto out; } } out: *next_index = index; return nr_found; } /** * radix_tree_gang_lookup - perform multiple lookup on a radix tree * @root: radix tree root * @results: where the results of the lookup are placed * @first_index: start the lookup from this key * @max_items: place up to this many items at *results * * Performs an index-ascending scan of the tree for present items. Places * them at *@results and returns the number of items which were placed at * *@results. * * The implementation is naive. */ unsigned int radix_tree_gang_lookup(struct radix_tree_root *root, void **results, unsigned long first_index, unsigned int max_items) { const unsigned long max_index = radix_tree_maxindex(root->height); unsigned long cur_index = first_index; unsigned int ret = 0; while (ret < max_items) { unsigned int nr_found; unsigned long next_index; /* Index of next search */ if (cur_index > max_index) break; nr_found = __lookup(root, results + ret, cur_index, max_items - ret, &next_index); ret += nr_found; if (next_index == 0) break; cur_index = next_index; } return ret; } /** * radix_tree_gang_lookup_ex - perform multiple lookup on a radix tree * @root: radix tree root * @results: where the results of the lookup are placed * @first_index: start the lookup from this key * @last_index: don't lookup past this key * @max_items: place up to this many items at *results * * Performs an index-ascending scan of the tree for present items starting * @first_index until @last_index up to as many as @max_items. Places * them at *@results and returns the number of items which were placed * at *@results. * * The implementation is naive. */ unsigned int radix_tree_gang_lookup_ex(struct radix_tree_root *root, void **results, unsigned long first_index, unsigned long last_index, unsigned int max_items) { const unsigned long max_index = radix_tree_maxindex(root->height); unsigned long cur_index = first_index; unsigned int ret = 0; while (ret < max_items && cur_index < last_index) { unsigned int nr_found; unsigned long next_index; /* Index of next search */ if (cur_index > max_index) break; nr_found = __lookup(root, results + ret, cur_index, max_items - ret, &next_index); ret += nr_found; if (next_index == 0) break; cur_index = next_index; } return ret; } #ifdef RADIX_TREE_TAGS static unsigned int __lookup_tag(struct radix_tree_root *root, void **results, unsigned long index, unsigned int max_items, unsigned long *next_index, unsigned int tag) { unsigned int nr_found = 0; unsigned int shift; unsigned int height = root->height; struct radix_tree_node *slot; shift = (height - 1) * RADIX_TREE_MAP_SHIFT; slot = root->rnode; while (height > 0) { unsigned long i = (index >> shift) & RADIX_TREE_MAP_MASK; for ( ; i < RADIX_TREE_MAP_SIZE; i++) { if (tag_get(slot, tag, i)) { ASSERT(slot->slots[i] != NULL); break; } index &= ~((1UL << shift) - 1); index += 1UL << shift; if (index == 0) goto out; /* 32-bit wraparound */ } if (i == RADIX_TREE_MAP_SIZE) goto out; height--; if (height == 0) { /* Bottom level: grab some items */ unsigned long j = index & RADIX_TREE_MAP_MASK; for ( ; j < RADIX_TREE_MAP_SIZE; j++) { index++; if (tag_get(slot, tag, j)) { ASSERT(slot->slots[j] != NULL); results[nr_found++] = slot->slots[j]; if (nr_found == max_items) goto out; } } } shift -= RADIX_TREE_MAP_SHIFT; slot = slot->slots[i]; } out: *next_index = index; return nr_found; } /** * radix_tree_gang_lookup_tag - perform multiple lookup on a radix tree * based on a tag * @root: radix tree root * @results: where the results of the lookup are placed * @first_index: start the lookup from this key * @max_items: place up to this many items at *results * @tag: the tag index (< RADIX_TREE_MAX_TAGS) * * Performs an index-ascending scan of the tree for present items which * have the tag indexed by @tag set. Places the items at *@results and * returns the number of items which were placed at *@results. */ unsigned int radix_tree_gang_lookup_tag(struct radix_tree_root *root, void **results, unsigned long first_index, unsigned int max_items, unsigned int tag) { const unsigned long max_index = radix_tree_maxindex(root->height); unsigned long cur_index = first_index; unsigned int ret = 0; while (ret < max_items) { unsigned int nr_found; unsigned long next_index; /* Index of next search */ if (cur_index > max_index) break; nr_found = __lookup_tag(root, results + ret, cur_index, max_items - ret, &next_index, tag); ret += nr_found; if (next_index == 0) break; cur_index = next_index; } return ret; } #endif /** * radix_tree_shrink - shrink height of a radix tree to minimal * @root radix tree root */ static inline void radix_tree_shrink(struct radix_tree_root *root) { /* try to shrink tree height */ while (root->height > 1 && root->rnode->count == 1 && root->rnode->slots[0]) { struct radix_tree_node *to_free = root->rnode; root->rnode = to_free->slots[0]; root->height--; /* must only free zeroed nodes into the slab */ #ifdef RADIX_TREE_TAGS tag_clear(to_free, 0, 0); tag_clear(to_free, 1, 0); #endif to_free->slots[0] = NULL; to_free->count = 0; radix_tree_node_free(to_free); } } /** * radix_tree_delete - delete an item from a radix tree * @root: radix tree root * @index: index key * * Remove the item at @index from the radix tree rooted at @root. * * Returns the address of the deleted item, or NULL if it was not present. */ void *radix_tree_delete(struct radix_tree_root *root, unsigned long index) { struct radix_tree_path path[RADIX_TREE_MAX_PATH + 1], *pathp = path; struct radix_tree_path *orig_pathp; struct radix_tree_node *slot; unsigned int height, shift; void *ret = NULL; #ifdef RADIX_TREE_TAGS char tags[RADIX_TREE_MAX_TAGS]; int nr_cleared_tags; int tag; #endif int offset; height = root->height; if (index > radix_tree_maxindex(height)) goto out; shift = (height - 1) * RADIX_TREE_MAP_SHIFT; pathp->node = NULL; slot = root->rnode; for ( ; height > 0; height--) { if (slot == NULL) goto out; pathp++; offset = (index >> shift) & RADIX_TREE_MAP_MASK; pathp->offset = offset; pathp->node = slot; slot = slot->slots[offset]; shift -= RADIX_TREE_MAP_SHIFT; } ret = slot; if (ret == NULL) goto out; orig_pathp = pathp; #ifdef RADIX_TREE_TAGS /* * Clear all tags associated with the just-deleted item */ nr_cleared_tags = 0; for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++) { tags[tag] = 1; if (tag_get(pathp->node, tag, pathp->offset)) { tag_clear(pathp->node, tag, pathp->offset); if (!any_tag_set(pathp->node, tag)) { tags[tag] = 0; nr_cleared_tags++; } } } for (pathp--; nr_cleared_tags && pathp->node; pathp--) { for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++) { if (tags[tag]) continue; tag_clear(pathp->node, tag, pathp->offset); if (any_tag_set(pathp->node, tag)) { tags[tag] = 1; nr_cleared_tags--; } } } #endif /* Now free the nodes we do not need anymore */ for (pathp = orig_pathp; pathp->node; pathp--) { pathp->node->slots[pathp->offset] = NULL; pathp->node->count--; if (pathp->node->count) { if (pathp->node == root->rnode) radix_tree_shrink(root); goto out; } /* Node with zero slots in use so free it */ radix_tree_node_free(pathp->node); } root->rnode = NULL; root->height = 0; out: return ret; } #ifdef RADIX_TREE_TAGS /** * radix_tree_tagged - test whether any items in the tree are tagged * @root: radix tree root * @tag: tag to test */ int radix_tree_tagged(struct radix_tree_root *root, unsigned int tag) { struct radix_tree_node *rnode; rnode = root->rnode; if (!rnode) return 0; return any_tag_set(rnode, tag); } #endif static unsigned long __maxindex(unsigned int height) { unsigned int tmp = height * RADIX_TREE_MAP_SHIFT; unsigned long index = (~0UL >> (RADIX_TREE_INDEX_BITS - tmp - 1)) >> 1; if (tmp >= RADIX_TREE_INDEX_BITS) index = ~0UL; return index; } static void radix_tree_init_maxindex(void) { unsigned int i; for (i = 0; i < ARRAY_SIZE(height_to_maxindex); i++) height_to_maxindex[i] = __maxindex(i); } void radix_tree_init(void) { radix_tree_init_maxindex(); } partclone-0.2.86/src/xfs/radix-tree.h000066400000000000000000000050641262102574200174100ustar00rootroot00000000000000/* * Copyright (C) 2001 Momchil Velikov * Portions Copyright (C) 2001 Christoph Hellwig * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef __XFS_SUPPORT_RADIX_TREE_H__ #define __XFS_SUPPORT_RADIX_TREE_H__ #define RADIX_TREE_TAGS struct radix_tree_root { unsigned int height; struct radix_tree_node *rnode; }; #define RADIX_TREE_INIT(mask) { \ .height = 0, \ .rnode = NULL, \ } #define RADIX_TREE(name, mask) \ struct radix_tree_root name = RADIX_TREE_INIT(mask) #define INIT_RADIX_TREE(root, mask) \ do { \ (root)->height = 0; \ (root)->rnode = NULL; \ } while (0) #ifdef RADIX_TREE_TAGS #define RADIX_TREE_MAX_TAGS 2 #endif int radix_tree_insert(struct radix_tree_root *, unsigned long, void *); void *radix_tree_lookup(struct radix_tree_root *, unsigned long); void **radix_tree_lookup_slot(struct radix_tree_root *, unsigned long); void *radix_tree_lookup_first(struct radix_tree_root *, unsigned long *); void *radix_tree_delete(struct radix_tree_root *, unsigned long); unsigned int radix_tree_gang_lookup(struct radix_tree_root *root, void **results, unsigned long first_index, unsigned int max_items); unsigned int radix_tree_gang_lookup_ex(struct radix_tree_root *root, void **results, unsigned long first_index, unsigned long last_index, unsigned int max_items); void radix_tree_init(void); #ifdef RADIX_TREE_TAGS void *radix_tree_tag_set(struct radix_tree_root *root, unsigned long index, unsigned int tag); void *radix_tree_tag_clear(struct radix_tree_root *root, unsigned long index, unsigned int tag); int radix_tree_tag_get(struct radix_tree_root *root, unsigned long index, unsigned int tag); unsigned int radix_tree_gang_lookup_tag(struct radix_tree_root *root, void **results, unsigned long first_index, unsigned int max_items, unsigned int tag); int radix_tree_tagged(struct radix_tree_root *root, unsigned int tag); #endif #endif /* __XFS_SUPPORT_RADIX_TREE_H__ */ partclone-0.2.86/src/xfs/rdwr.c000066400000000000000000000727421262102574200163240ustar00rootroot00000000000000/* * Copyright (c) 2000-2006 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "libxfs_priv.h" #include "init.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_mount.h" #include "xfs_inode_buf.h" #include "xfs_inode_fork.h" #include "xfs_inode.h" #include "xfs_trans.h" #include "libxfs.h" /* for LIBXFS_EXIT_ON_FAILURE */ /* * Important design/architecture note: * * The userspace code that uses the buffer cache is much less constrained than * the kernel code. The userspace code is pretty nasty in places, especially * when it comes to buffer error handling. Very little of the userspace code * outside libxfs clears bp->b_error - very little code even checks it - so the * libxfs code is tripping on stale errors left by the userspace code. * * We can't clear errors or zero buffer contents in libxfs_getbuf-* like we do * in the kernel, because those functions are used by the libxfs_readbuf_* * functions and hence need to leave the buffers unchanged on cache hits. This * is actually the only way to gather a write error from a libxfs_writebuf() * call - you need to get the buffer again so you can check bp->b_error field - * assuming that the buffer is still in the cache when you check, that is. * * This is very different to the kernel code which does not release buffers on a * write so we can wait on IO and check errors. The kernel buffer cache also * guarantees a buffer of a known initial state from xfs_buf_get() even on a * cache hit. * * IOWs, userspace is behaving quite differently to the kernel and as a result * it leaks errors from reads, invalidations and writes through * libxfs_getbuf/libxfs_readbuf. * * The result of this is that until the userspace code outside libxfs is cleaned * up, functions that release buffers from userspace control (i.e * libxfs_writebuf/libxfs_putbuf) need to zero bp->b_error to prevent * propagation of stale errors into future buffer operations. */ #define BDSTRAT_SIZE (256 * 1024) #define IO_BCOMPARE_CHECK void libxfs_device_zero(struct xfs_buftarg *btp, xfs_daddr_t start, uint len) { xfs_off_t start_offset, end_offset, offset; ssize_t zsize, bytes; char *z; int fd; zsize = min(BDSTRAT_SIZE, BBTOB(len)); if ((z = memalign(libxfs_device_alignment(), zsize)) == NULL) { fprintf(stderr, _("%s: %s can't memalign %d bytes: %s\n"), progname, __FUNCTION__, (int)zsize, strerror(errno)); exit(1); } memset(z, 0, zsize); fd = libxfs_device_to_fd(btp->dev); start_offset = LIBXFS_BBTOOFF64(start); if ((lseek64(fd, start_offset, SEEK_SET)) < 0) { fprintf(stderr, _("%s: %s seek to offset %llu failed: %s\n"), progname, __FUNCTION__, (unsigned long long)start_offset, strerror(errno)); exit(1); } end_offset = LIBXFS_BBTOOFF64(start + len) - start_offset; for (offset = 0; offset < end_offset; ) { bytes = min((ssize_t)(end_offset - offset), zsize); if ((bytes = write(fd, z, bytes)) < 0) { fprintf(stderr, _("%s: %s write failed: %s\n"), progname, __FUNCTION__, strerror(errno)); exit(1); } else if (bytes == 0) { fprintf(stderr, _("%s: %s not progressing?\n"), progname, __FUNCTION__); exit(1); } offset += bytes; } free(z); } static void unmount_record(void *p) { xlog_op_header_t *op = (xlog_op_header_t *)p; /* the data section must be 32 bit size aligned */ struct { __uint16_t magic; __uint16_t pad1; __uint32_t pad2; /* may as well make it 64 bits */ } magic = { XLOG_UNMOUNT_TYPE, 0, 0 }; memset(p, 0, BBSIZE); op->oh_tid = cpu_to_be32(1); op->oh_len = cpu_to_be32(sizeof(magic)); op->oh_clientid = XFS_LOG; op->oh_flags = XLOG_UNMOUNT_TRANS; op->oh_res2 = 0; /* and the data for this op */ memcpy((char *)p + sizeof(xlog_op_header_t), &magic, sizeof(magic)); } static char *next(char *ptr, int offset, void *private) { xfs_buf_t *buf = (xfs_buf_t *)private; if (XFS_BUF_COUNT(buf) < (int)(ptr - XFS_BUF_PTR(buf)) + offset) abort(); return ptr + offset; } int libxfs_log_clear( struct xfs_buftarg *btp, xfs_daddr_t start, uint length, uuid_t *fs_uuid, int version, int sunit, int fmt) { xfs_buf_t *bp; int len; if (!btp->dev || !fs_uuid) return -EINVAL; /* first zero the log */ libxfs_device_zero(btp, start, length); /* then write a log record header */ len = ((version == 2) && sunit) ? BTOBB(sunit) : 2; len = MAX(len, 2); bp = libxfs_getbufr(btp, start, len); libxfs_log_header(XFS_BUF_PTR(bp), fs_uuid, version, sunit, fmt, next, bp); bp->b_flags |= LIBXFS_B_DIRTY; libxfs_putbufr(bp); return 0; } int libxfs_log_header( char *caddr, uuid_t *fs_uuid, int version, int sunit, int fmt, libxfs_get_block_t *nextfunc, void *private) { xlog_rec_header_t *head = (xlog_rec_header_t *)caddr; char *p = caddr; __be32 cycle_lsn; int i, len; len = ((version == 2) && sunit) ? BTOBB(sunit) : 1; /* note that oh_tid actually contains the cycle number * and the tid is stored in h_cycle_data[0] - that's the * way things end up on disk. */ memset(p, 0, BBSIZE); head->h_magicno = cpu_to_be32(XLOG_HEADER_MAGIC_NUM); head->h_cycle = cpu_to_be32(1); head->h_version = cpu_to_be32(version); if (len != 1) head->h_len = cpu_to_be32(sunit - BBSIZE); else head->h_len = cpu_to_be32(20); head->h_crc = cpu_to_le32(0); head->h_prev_block = cpu_to_be32(-1); head->h_num_logops = cpu_to_be32(1); head->h_cycle_data[0] = cpu_to_be32(0xb0c0d0d0); head->h_fmt = cpu_to_be32(fmt); head->h_size = cpu_to_be32(XLOG_HEADER_CYCLE_SIZE); head->h_lsn = cpu_to_be64(xlog_assign_lsn(1, 0)); head->h_tail_lsn = cpu_to_be64(xlog_assign_lsn(1, 0)); memcpy(&head->h_fs_uuid, fs_uuid, sizeof(uuid_t)); len = MAX(len, 2); p = nextfunc(p, BBSIZE, private); unmount_record(p); cycle_lsn = CYCLE_LSN_DISK(head->h_lsn); for (i = 2; i < len; i++) { p = nextfunc(p, BBSIZE, private); memset(p, 0, BBSIZE); *(__be32 *)p = cycle_lsn; } return BBTOB(len); } /* * Simple I/O (buffer cache) interface */ #ifdef XFS_BUF_TRACING #undef libxfs_readbuf #undef libxfs_readbuf_map #undef libxfs_writebuf #undef libxfs_getbuf #undef libxfs_getbuf_map #undef libxfs_getbuf_flags #undef libxfs_putbuf xfs_buf_t *libxfs_readbuf(struct xfs_buftarg *, xfs_daddr_t, int, int, const struct xfs_buf_ops *); xfs_buf_t *libxfs_readbuf_map(struct xfs_buftarg *, struct xfs_buf_map *, int, int, const struct xfs_buf_ops *); int libxfs_writebuf(xfs_buf_t *, int); xfs_buf_t *libxfs_getbuf(struct xfs_buftarg *, xfs_daddr_t, int); xfs_buf_t *libxfs_getbuf_map(struct xfs_buftarg *, struct xfs_buf_map *, int, int); xfs_buf_t *libxfs_getbuf_flags(struct xfs_buftarg *, xfs_daddr_t, int, unsigned int); void libxfs_putbuf (xfs_buf_t *); #define __add_trace(bp, func, file, line) \ do { \ if (bp) { \ (bp)->b_func = (func); \ (bp)->b_file = (file); \ (bp)->b_line = (line); \ } \ } while (0) xfs_buf_t * libxfs_trace_readbuf(const char *func, const char *file, int line, struct xfs_buftarg *btp, xfs_daddr_t blkno, int len, int flags, const struct xfs_buf_ops *ops) { xfs_buf_t *bp = libxfs_readbuf(btp, blkno, len, flags, ops); __add_trace(bp, func, file, line); return bp; } xfs_buf_t * libxfs_trace_readbuf_map(const char *func, const char *file, int line, struct xfs_buftarg *btp, struct xfs_buf_map *map, int nmaps, int flags, const struct xfs_buf_ops *ops) { xfs_buf_t *bp = libxfs_readbuf_map(btp, map, nmaps, flags, ops); __add_trace(bp, func, file, line); return bp; } int libxfs_trace_writebuf(const char *func, const char *file, int line, xfs_buf_t *bp, int flags) { __add_trace(bp, func, file, line); return libxfs_writebuf(bp, flags); } xfs_buf_t * libxfs_trace_getbuf(const char *func, const char *file, int line, struct xfs_buftarg *btp, xfs_daddr_t blkno, int len) { xfs_buf_t *bp = libxfs_getbuf(btp, blkno, len); __add_trace(bp, func, file, line); return bp; } xfs_buf_t * libxfs_trace_getbuf_map(const char *func, const char *file, int line, struct xfs_buftarg *btp, struct xfs_buf_map *map, int nmaps, int flags) { xfs_buf_t *bp = libxfs_getbuf_map(btp, map, nmaps, flags); __add_trace(bp, func, file, line); return bp; } xfs_buf_t * libxfs_trace_getbuf_flags(const char *func, const char *file, int line, struct xfs_buftarg *btp, xfs_daddr_t blkno, int len, unsigned int flags) { xfs_buf_t *bp = libxfs_getbuf_flags(btp, blkno, len, flags); __add_trace(bp, func, file, line); return bp; } void libxfs_trace_putbuf(const char *func, const char *file, int line, xfs_buf_t *bp) { __add_trace(bp, func, file, line); libxfs_putbuf(bp); } #endif xfs_buf_t * libxfs_getsb(xfs_mount_t *mp, int flags) { return libxfs_readbuf(mp->m_ddev_targp, XFS_SB_DADDR, XFS_FSS_TO_BB(mp, 1), flags, &xfs_sb_buf_ops); } kmem_zone_t *xfs_buf_zone; static struct cache_mru xfs_buf_freelist = {{&xfs_buf_freelist.cm_list, &xfs_buf_freelist.cm_list}, 0, PTHREAD_MUTEX_INITIALIZER }; /* * The bufkey is used to pass the new buffer information to the cache object * allocation routine. Because discontiguous buffers need to pass different * information, we need fields to pass that information. However, because the * blkno and bblen is needed for the initial cache entry lookup (i.e. for * bcompare) the fact that the map/nmaps is non-null to switch to discontiguous * buffer initialisation instead of a contiguous buffer. */ struct xfs_bufkey { struct xfs_buftarg *buftarg; xfs_daddr_t blkno; unsigned int bblen; struct xfs_buf_map *map; int nmaps; }; /* 2^63 + 2^61 - 2^57 + 2^54 - 2^51 - 2^18 + 1 */ #define GOLDEN_RATIO_PRIME 0x9e37fffffffc0001UL #define CACHE_LINE_SIZE 64 static unsigned int libxfs_bhash(cache_key_t key, unsigned int hashsize, unsigned int hashshift) { uint64_t hashval = ((struct xfs_bufkey *)key)->blkno; uint64_t tmp; tmp = hashval ^ (GOLDEN_RATIO_PRIME + hashval) / CACHE_LINE_SIZE; tmp = tmp ^ ((tmp ^ GOLDEN_RATIO_PRIME) >> hashshift); return tmp % hashsize; } static int libxfs_bcompare(struct cache_node *node, cache_key_t key) { struct xfs_buf *bp = (struct xfs_buf *)node; struct xfs_bufkey *bkey = (struct xfs_bufkey *)key; if (bp->b_target->dev == bkey->buftarg->dev && bp->b_bn == bkey->blkno) { if (bp->b_bcount == BBTOB(bkey->bblen)) return CACHE_HIT; #ifdef IO_BCOMPARE_CHECK if (!(libxfs_bcache->c_flags & CACHE_MISCOMPARE_PURGE)) { fprintf(stderr, "%lx: Badness in key lookup (length)\n" "bp=(bno 0x%llx, len %u bytes) key=(bno 0x%llx, len %u bytes)\n", pthread_self(), (unsigned long long)bp->b_bn, (int)bp->b_bcount, (unsigned long long)bkey->blkno, BBTOB(bkey->bblen)); } #endif return CACHE_PURGE; } return CACHE_MISS; } void libxfs_bprint(xfs_buf_t *bp) { fprintf(stderr, "Buffer 0x%p blkno=%llu bytes=%u flags=0x%x count=%u\n", bp, (unsigned long long)bp->b_bn, (unsigned)bp->b_bcount, bp->b_flags, bp->b_node.cn_count); } static void __initbuf(xfs_buf_t *bp, struct xfs_buftarg *btp, xfs_daddr_t bno, unsigned int bytes) { bp->b_flags = 0; bp->b_bn = bno; bp->b_bcount = bytes; bp->b_length = BTOBB(bytes); bp->b_target = btp; bp->b_error = 0; if (!bp->b_addr) bp->b_addr = memalign(libxfs_device_alignment(), bytes); if (!bp->b_addr) { fprintf(stderr, _("%s: %s can't memalign %u bytes: %s\n"), progname, __FUNCTION__, bytes, strerror(errno)); exit(1); } memset(bp->b_addr, 0, bytes); #ifdef XFS_BUF_TRACING list_head_init(&bp->b_lock_list); #endif pthread_mutex_init(&bp->b_lock, NULL); bp->b_holder = 0; bp->b_recur = 0; bp->b_ops = NULL; } static void libxfs_initbuf(xfs_buf_t *bp, struct xfs_buftarg *btp, xfs_daddr_t bno, unsigned int bytes) { __initbuf(bp, btp, bno, bytes); } static void libxfs_initbuf_map(xfs_buf_t *bp, struct xfs_buftarg *btp, struct xfs_buf_map *map, int nmaps) { unsigned int bytes = 0; int i; bytes = sizeof(struct xfs_buf_map) * nmaps; bp->b_map = malloc(bytes); if (!bp->b_map) { fprintf(stderr, _("%s: %s can't malloc %u bytes: %s\n"), progname, __FUNCTION__, bytes, strerror(errno)); exit(1); } bp->b_nmaps = nmaps; bytes = 0; for ( i = 0; i < nmaps; i++) { bp->b_map[i].bm_bn = map[i].bm_bn; bp->b_map[i].bm_len = map[i].bm_len; bytes += BBTOB(map[i].bm_len); } __initbuf(bp, btp, map[0].bm_bn, bytes); bp->b_flags |= LIBXFS_B_DISCONTIG; } xfs_buf_t * __libxfs_getbufr(int blen) { xfs_buf_t *bp; /* * first look for a buffer that can be used as-is, * if one cannot be found, see if there is a buffer, * and if so, free its buffer and set b_addr to NULL * before calling libxfs_initbuf. */ pthread_mutex_lock(&xfs_buf_freelist.cm_mutex); if (!list_empty(&xfs_buf_freelist.cm_list)) { list_for_each_entry(bp, &xfs_buf_freelist.cm_list, b_node.cn_mru) { if (bp->b_bcount == blen) { list_del_init(&bp->b_node.cn_mru); break; } } if (&bp->b_node.cn_mru == &xfs_buf_freelist.cm_list) { bp = list_entry(xfs_buf_freelist.cm_list.next, xfs_buf_t, b_node.cn_mru); list_del_init(&bp->b_node.cn_mru); free(bp->b_addr); bp->b_addr = NULL; free(bp->b_map); bp->b_map = NULL; } } else bp = kmem_zone_zalloc(xfs_buf_zone, 0); pthread_mutex_unlock(&xfs_buf_freelist.cm_mutex); bp->b_ops = NULL; return bp; } xfs_buf_t * libxfs_getbufr(struct xfs_buftarg *btp, xfs_daddr_t blkno, int bblen) { xfs_buf_t *bp; int blen = BBTOB(bblen); bp =__libxfs_getbufr(blen); if (bp) libxfs_initbuf(bp, btp, blkno, blen); #ifdef IO_DEBUG printf("%lx: %s: allocated %u bytes buffer, key=0x%llx(0x%llx), %p\n", pthread_self(), __FUNCTION__, blen, (long long)LIBXFS_BBTOOFF64(blkno), (long long)blkno, bp); #endif return bp; } xfs_buf_t * libxfs_getbufr_map(struct xfs_buftarg *btp, xfs_daddr_t blkno, int bblen, struct xfs_buf_map *map, int nmaps) { xfs_buf_t *bp; int blen = BBTOB(bblen); if (!map || !nmaps) { fprintf(stderr, _("%s: %s invalid map %p or nmaps %d\n"), progname, __FUNCTION__, map, nmaps); exit(1); } if (blkno != map[0].bm_bn) { fprintf(stderr, _("%s: %s map blkno 0x%llx doesn't match key 0x%llx\n"), progname, __FUNCTION__, (long long)map[0].bm_bn, (long long)blkno); exit(1); } bp =__libxfs_getbufr(blen); if (bp) libxfs_initbuf_map(bp, btp, map, nmaps); #ifdef IO_DEBUG printf("%lx: %s: allocated %u bytes buffer, key=0x%llx(0x%llx), %p\n", pthread_self(), __FUNCTION__, blen, (long long)LIBXFS_BBTOOFF64(blkno), (long long)blkno, bp); #endif return bp; } #ifdef XFS_BUF_TRACING struct list_head lock_buf_list = {&lock_buf_list, &lock_buf_list}; int lock_buf_count = 0; #endif extern int use_xfs_buf_lock; static struct xfs_buf * __cache_lookup(struct xfs_bufkey *key, unsigned int flags) { struct xfs_buf *bp; cache_node_get(libxfs_bcache, key, (struct cache_node **)&bp); if (!bp) return NULL; if (use_xfs_buf_lock) { int ret; ret = pthread_mutex_trylock(&bp->b_lock); if (ret) { ASSERT(ret == EAGAIN); if (flags & LIBXFS_GETBUF_TRYLOCK) goto out_put; if (pthread_equal(bp->b_holder, pthread_self())) { fprintf(stderr, _("Warning: recursive buffer locking at block %" PRIu64 " detected\n"), key->blkno); bp->b_recur++; return bp; } else { pthread_mutex_lock(&bp->b_lock); } } bp->b_holder = pthread_self(); } cache_node_set_priority(libxfs_bcache, (struct cache_node *)bp, cache_node_get_priority((struct cache_node *)bp) - CACHE_PREFETCH_PRIORITY); #ifdef XFS_BUF_TRACING pthread_mutex_lock(&libxfs_bcache->c_mutex); lock_buf_count++; list_add(&bp->b_lock_list, &lock_buf_list); pthread_mutex_unlock(&libxfs_bcache->c_mutex); #endif #ifdef IO_DEBUG printf("%lx %s: hit buffer %p for bno = 0x%llx/0x%llx\n", pthread_self(), __FUNCTION__, bp, bp->b_bn, (long long)LIBXFS_BBTOOFF64(key->blkno)); #endif return bp; out_put: cache_node_put(libxfs_bcache, (struct cache_node *)bp); return NULL; } struct xfs_buf * libxfs_getbuf_flags(struct xfs_buftarg *btp, xfs_daddr_t blkno, int len, unsigned int flags) { struct xfs_bufkey key = {0}; key.buftarg = btp; key.blkno = blkno; key.bblen = len; return __cache_lookup(&key, flags); } /* * Clean the buffer flags for libxfs_getbuf*(), which wants to return * an unused buffer with clean state. This prevents CRC errors on a * re-read of a corrupt block that was prefetched and freed. This * can happen with a massively corrupt directory that is discarded, * but whose blocks are then recycled into expanding lost+found. * * Note however that if the buffer's dirty (prefetch calls getbuf) * we'll leave the state alone because we don't want to discard blocks * that have been fixed. */ static void reset_buf_state( struct xfs_buf *bp) { if (bp && !(bp->b_flags & LIBXFS_B_DIRTY)) bp->b_flags &= ~(LIBXFS_B_UNCHECKED | LIBXFS_B_STALE | LIBXFS_B_UPTODATE); } struct xfs_buf * libxfs_getbuf(struct xfs_buftarg *btp, xfs_daddr_t blkno, int len) { struct xfs_buf *bp; bp = libxfs_getbuf_flags(btp, blkno, len, 0); reset_buf_state(bp); return bp; } static struct xfs_buf * __libxfs_getbuf_map(struct xfs_buftarg *btp, struct xfs_buf_map *map, int nmaps, int flags) { struct xfs_bufkey key = {0}; int i; if (nmaps == 1) return libxfs_getbuf_flags(btp, map[0].bm_bn, map[0].bm_len, flags); key.buftarg = btp; key.blkno = map[0].bm_bn; for (i = 0; i < nmaps; i++) { key.bblen += map[i].bm_len; } key.map = map; key.nmaps = nmaps; return __cache_lookup(&key, flags); } struct xfs_buf * libxfs_getbuf_map(struct xfs_buftarg *btp, struct xfs_buf_map *map, int nmaps, int flags) { struct xfs_buf *bp; bp = __libxfs_getbuf_map(btp, map, nmaps, flags); reset_buf_state(bp); return bp; } void libxfs_putbuf(xfs_buf_t *bp) { /* * ensure that any errors on this use of the buffer don't carry * over to the next user. */ bp->b_error = 0; #ifdef XFS_BUF_TRACING pthread_mutex_lock(&libxfs_bcache->c_mutex); lock_buf_count--; ASSERT(lock_buf_count >= 0); list_del_init(&bp->b_lock_list); pthread_mutex_unlock(&libxfs_bcache->c_mutex); #endif if (use_xfs_buf_lock) { if (bp->b_recur) { bp->b_recur--; } else { bp->b_holder = 0; pthread_mutex_unlock(&bp->b_lock); } } cache_node_put(libxfs_bcache, (struct cache_node *)bp); } void libxfs_purgebuf(xfs_buf_t *bp) { struct xfs_bufkey key = {0}; key.buftarg = bp->b_target; key.blkno = bp->b_bn; key.bblen = bp->b_length; cache_node_purge(libxfs_bcache, &key, (struct cache_node *)bp); } static struct cache_node * libxfs_balloc(cache_key_t key) { struct xfs_bufkey *bufkey = (struct xfs_bufkey *)key; if (bufkey->map) return (struct cache_node *) libxfs_getbufr_map(bufkey->buftarg, bufkey->blkno, bufkey->bblen, bufkey->map, bufkey->nmaps); return (struct cache_node *)libxfs_getbufr(bufkey->buftarg, bufkey->blkno, bufkey->bblen); } static int __read_buf(int fd, void *buf, int len, off64_t offset, int flags) { int sts; sts = pread64(fd, buf, len, offset); if (sts < 0) { int error = -errno; fprintf(stderr, _("%s: read failed: %s\n"), progname, strerror(error)); if (flags & LIBXFS_EXIT_ON_FAILURE) exit(1); return error; } else if (sts != len) { fprintf(stderr, _("%s: error - read only %d of %d bytes\n"), progname, sts, len); if (flags & LIBXFS_EXIT_ON_FAILURE) exit(1); return -EIO; } return 0; } int libxfs_readbufr(struct xfs_buftarg *btp, xfs_daddr_t blkno, xfs_buf_t *bp, int len, int flags) { int fd = libxfs_device_to_fd(btp->dev); int bytes = BBTOB(len); int error; ASSERT(BBTOB(len) <= bp->b_bcount); error = __read_buf(fd, bp->b_addr, bytes, LIBXFS_BBTOOFF64(blkno), flags); if (!error && bp->b_target->dev == btp->dev && bp->b_bn == blkno && bp->b_bcount == bytes) bp->b_flags |= LIBXFS_B_UPTODATE; #ifdef IO_DEBUG printf("%lx: %s: read %u bytes, error %d, blkno=0x%llx(0x%llx), %p\n", pthread_self(), __FUNCTION__, bytes, error, (long long)LIBXFS_BBTOOFF64(blkno), (long long)blkno, bp); #endif return error; } void libxfs_readbuf_verify(struct xfs_buf *bp, const struct xfs_buf_ops *ops) { if (!ops) return; bp->b_ops = ops; bp->b_ops->verify_read(bp); bp->b_flags &= ~LIBXFS_B_UNCHECKED; } xfs_buf_t * libxfs_readbuf(struct xfs_buftarg *btp, xfs_daddr_t blkno, int len, int flags, const struct xfs_buf_ops *ops) { xfs_buf_t *bp; int error; bp = libxfs_getbuf_flags(btp, blkno, len, 0); if (!bp) return NULL; /* * if the buffer was prefetched, it is likely that it was not validated. * Hence if we are supplied an ops function and the buffer is marked as * unchecked, we need to validate it now. * * We do this verification even if the buffer is dirty - the * verification is almost certainly going to fail the CRC check in this * case as a dirty buffer has not had the CRC recalculated. However, we * should not be dirtying unchecked buffers and therefore failing it * here because it's dirty and unchecked indicates we've screwed up * somewhere else. */ bp->b_error = 0; if ((bp->b_flags & (LIBXFS_B_UPTODATE|LIBXFS_B_DIRTY))) { if (bp->b_flags & LIBXFS_B_UNCHECKED) libxfs_readbuf_verify(bp, ops); return bp; } /* * Set the ops on a cache miss (i.e. first physical read) as the * verifier may change the ops to match the type of buffer it contains. * A cache hit might reset the verifier to the original type if we set * it again, but it won't get called again and set to match the buffer * contents. *cough* xfs_da_node_buf_ops *cough*. */ error = libxfs_readbufr(btp, blkno, bp, len, flags); if (error) bp->b_error = error; else libxfs_readbuf_verify(bp, ops); return bp; } int libxfs_readbufr_map(struct xfs_buftarg *btp, struct xfs_buf *bp, int flags) { int fd; int error = 0; char *buf; int i; fd = libxfs_device_to_fd(btp->dev); buf = bp->b_addr; for (i = 0; i < bp->b_nmaps; i++) { off64_t offset = LIBXFS_BBTOOFF64(bp->b_map[i].bm_bn); int len = BBTOB(bp->b_map[i].bm_len); error = __read_buf(fd, buf, len, offset, flags); if (error) { bp->b_error = error; break; } buf += len; } if (!error) bp->b_flags |= LIBXFS_B_UPTODATE; #ifdef IO_DEBUG printf("%lx: %s: read %u bytes, error %d, blkno=0x%llx(0x%llx), %p\n", pthread_self(), __FUNCTION__, , error, (long long)LIBXFS_BBTOOFF64(blkno), (long long)blkno, bp); #endif return error; } struct xfs_buf * libxfs_readbuf_map(struct xfs_buftarg *btp, struct xfs_buf_map *map, int nmaps, int flags, const struct xfs_buf_ops *ops) { struct xfs_buf *bp; int error = 0; if (nmaps == 1) return libxfs_readbuf(btp, map[0].bm_bn, map[0].bm_len, flags, ops); bp = __libxfs_getbuf_map(btp, map, nmaps, 0); if (!bp) return NULL; bp->b_error = 0; if ((bp->b_flags & (LIBXFS_B_UPTODATE|LIBXFS_B_DIRTY))) { if (bp->b_flags & LIBXFS_B_UNCHECKED) libxfs_readbuf_verify(bp, ops); return bp; } error = libxfs_readbufr_map(btp, bp, flags); if (!error) libxfs_readbuf_verify(bp, ops); #ifdef IO_DEBUG printf("%lx: %s: read %lu bytes, error %d, blkno=%llu(%llu), %p\n", pthread_self(), __FUNCTION__, buf - (char *)bp->b_addr, error, (long long)LIBXFS_BBTOOFF64(bp->b_bn), (long long)bp->b_bn, bp); #endif return bp; } static int __write_buf(int fd, void *buf, int len, off64_t offset, int flags) { int sts; sts = pwrite64(fd, buf, len, offset); if (sts < 0) { int error = -errno; fprintf(stderr, _("%s: pwrite64 failed: %s\n"), progname, strerror(error)); if (flags & LIBXFS_B_EXIT) exit(1); return error; } else if (sts != len) { fprintf(stderr, _("%s: error - pwrite64 only %d of %d bytes\n"), progname, sts, len); if (flags & LIBXFS_B_EXIT) exit(1); return -EIO; } return 0; } int libxfs_writebufr(xfs_buf_t *bp) { int fd = libxfs_device_to_fd(bp->b_target->dev); int error = 0; /* * we never write buffers that are marked stale. This indicates they * contain data that has been invalidated, and even if the buffer is * dirty it must *never* be written. Verifiers are wonderful for finding * bugs like this. Make sure the error is obvious as to the cause. */ if (bp->b_flags & LIBXFS_B_STALE) { bp->b_error = -ESTALE; return bp->b_error; } /* * clear any pre-existing error status on the buffer. This can occur if * the buffer is corrupt on disk and the repair process doesn't clear * the error before fixing and writing it back. */ bp->b_error = 0; if (bp->b_ops) { bp->b_ops->verify_write(bp); if (bp->b_error) { fprintf(stderr, _("%s: write verifer failed on bno 0x%llx/0x%x\n"), __func__, (long long)bp->b_bn, bp->b_bcount); return bp->b_error; } } if (!(bp->b_flags & LIBXFS_B_DISCONTIG)) { error = __write_buf(fd, bp->b_addr, bp->b_bcount, LIBXFS_BBTOOFF64(bp->b_bn), bp->b_flags); } else { int i; char *buf = bp->b_addr; for (i = 0; i < bp->b_nmaps; i++) { off64_t offset = LIBXFS_BBTOOFF64(bp->b_map[i].bm_bn); int len = BBTOB(bp->b_map[i].bm_len); error = __write_buf(fd, buf, len, offset, bp->b_flags); if (error) { bp->b_error = error; break; } buf += len; } } #ifdef IO_DEBUG printf("%lx: %s: wrote %u bytes, blkno=%llu(%llu), %p, error %d\n", pthread_self(), __FUNCTION__, bp->b_bcount, (long long)LIBXFS_BBTOOFF64(bp->b_bn), (long long)bp->b_bn, bp, error); #endif if (!error) { bp->b_flags |= LIBXFS_B_UPTODATE; bp->b_flags &= ~(LIBXFS_B_DIRTY | LIBXFS_B_EXIT | LIBXFS_B_UNCHECKED); } return error; } int libxfs_writebuf_int(xfs_buf_t *bp, int flags) { /* * Clear any error hanging over from reading the buffer. This prevents * subsequent reads after this write from seeing stale errors. */ bp->b_error = 0; bp->b_flags &= ~LIBXFS_B_STALE; bp->b_flags |= (LIBXFS_B_DIRTY | flags); return 0; } int libxfs_writebuf(xfs_buf_t *bp, int flags) { #ifdef IO_DEBUG printf("%lx: %s: dirty blkno=%llu(%llu)\n", pthread_self(), __FUNCTION__, (long long)LIBXFS_BBTOOFF64(bp->b_bn), (long long)bp->b_bn); #endif /* * Clear any error hanging over from reading the buffer. This prevents * subsequent reads after this write from seeing stale errors. */ bp->b_error = 0; bp->b_flags &= ~LIBXFS_B_STALE; bp->b_flags |= (LIBXFS_B_DIRTY | flags); libxfs_putbuf(bp); return 0; } void libxfs_iomove(xfs_buf_t *bp, uint boff, int len, void *data, int flags) { #ifdef IO_DEBUG if (boff + len > bp->b_bcount) { printf("Badness, iomove out of range!\n" "bp=(bno 0x%llx, bytes %u) range=(boff %u, bytes %u)\n", (long long)bp->b_bn, bp->b_bcount, boff, len); abort(); } #endif switch (flags) { case LIBXFS_BZERO: memset(bp->b_addr + boff, 0, len); break; case LIBXFS_BREAD: memcpy(data, bp->b_addr + boff, len); break; case LIBXFS_BWRITE: memcpy(bp->b_addr + boff, data, len); break; } } static void libxfs_brelse(struct cache_node *node) { xfs_buf_t *bp = (xfs_buf_t *)node; if (bp != NULL) { if (bp->b_flags & LIBXFS_B_DIRTY) libxfs_writebufr(bp); pthread_mutex_lock(&xfs_buf_freelist.cm_mutex); list_add(&bp->b_node.cn_mru, &xfs_buf_freelist.cm_list); pthread_mutex_unlock(&xfs_buf_freelist.cm_mutex); } } static unsigned int libxfs_bulkrelse( struct cache *cache, struct list_head *list) { xfs_buf_t *bp; int count = 0; if (list_empty(list)) return 0 ; list_for_each_entry(bp, list, b_node.cn_mru) { if (bp->b_flags & LIBXFS_B_DIRTY) libxfs_writebufr(bp); count++; } pthread_mutex_lock(&xfs_buf_freelist.cm_mutex); __list_splice(list, &xfs_buf_freelist.cm_list); pthread_mutex_unlock(&xfs_buf_freelist.cm_mutex); return count; } static void libxfs_bflush(struct cache_node *node) { xfs_buf_t *bp = (xfs_buf_t *)node; if ((bp != NULL) && (bp->b_flags & LIBXFS_B_DIRTY)) libxfs_writebufr(bp); } void libxfs_putbufr(xfs_buf_t *bp) { libxfs_brelse((struct cache_node *)bp); } void libxfs_bcache_purge(void) { cache_purge(libxfs_bcache); } void libxfs_bcache_flush(void) { cache_flush(libxfs_bcache); } int libxfs_bcache_overflowed(void) { return cache_overflowed(libxfs_bcache); } struct cache_operations libxfs_bcache_operations = { .hash = libxfs_bhash, .alloc = libxfs_balloc, .flush = libxfs_bflush, .relse = libxfs_brelse, .compare = libxfs_bcompare, .bulkrelse = libxfs_bulkrelse }; /* * Inode cache stubs. */ extern kmem_zone_t *xfs_ili_zone; extern kmem_zone_t *xfs_inode_zone; int libxfs_iget(xfs_mount_t *mp, xfs_trans_t *tp, xfs_ino_t ino, uint lock_flags, xfs_inode_t **ipp, xfs_daddr_t bno) { xfs_inode_t *ip; int error = 0; ip = kmem_zone_zalloc(xfs_inode_zone, 0); if (!ip) return -ENOMEM; ip->i_ino = ino; ip->i_mount = mp; error = xfs_iread(mp, tp, ip, bno); if (error) { kmem_zone_free(xfs_inode_zone, ip); *ipp = NULL; return error; } /* * set up the inode ops structure that the libxfs code relies on */ if (S_ISDIR(ip->i_d.di_mode)) ip->d_ops = mp->m_dir_inode_ops; else ip->d_ops = mp->m_nondir_inode_ops; *ipp = ip; return 0; } static void libxfs_idestroy(xfs_inode_t *ip) { switch (ip->i_d.di_mode & S_IFMT) { case S_IFREG: case S_IFDIR: case S_IFLNK: libxfs_idestroy_fork(ip, XFS_DATA_FORK); break; } if (ip->i_afp) libxfs_idestroy_fork(ip, XFS_ATTR_FORK); } void libxfs_iput(xfs_inode_t *ip) { if (ip->i_itemp) kmem_zone_free(xfs_ili_zone, ip->i_itemp); ip->i_itemp = NULL; libxfs_idestroy(ip); kmem_zone_free(xfs_inode_zone, ip); } partclone-0.2.86/src/xfs/trans.c000066400000000000000000000465721262102574200164770ustar00rootroot00000000000000/* * Copyright (c) 2000-2001,2005-2006 Silicon Graphics, Inc. * Copyright (C) 2010 Red Hat, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_mount.h" #include "xfs_inode_buf.h" #include "xfs_inode_fork.h" #include "xfs_inode.h" #include "xfs_trans.h" #include "xfs_sb.h" static void xfs_trans_free_items(struct xfs_trans *tp); /* * Simple transaction interface */ kmem_zone_t *xfs_log_item_desc_zone; /* * Initialize the precomputed transaction reservation values * in the mount structure. */ void libxfs_trans_init( struct xfs_mount *mp) { xfs_trans_resv_calc(mp, &mp->m_resv); } /* * Add the given log item to the transaction's list of log items. * * The log item will now point to its new descriptor with its li_desc field. */ void libxfs_trans_add_item( struct xfs_trans *tp, struct xfs_log_item *lip) { struct xfs_log_item_desc *lidp; ASSERT(lip->li_mountp == tp->t_mountp); ASSERT(lip->li_ailp == tp->t_mountp->m_ail); lidp = calloc(sizeof(struct xfs_log_item_desc), 1); if (!lidp) { fprintf(stderr, _("%s: lidp calloc failed (%d bytes): %s\n"), progname, (int)sizeof(struct xfs_log_item_desc), strerror(errno)); exit(1); } lidp->lid_item = lip; lidp->lid_flags = 0; list_add_tail(&lidp->lid_trans, &tp->t_items); lip->li_desc = lidp; } /* * Unlink and free the given descriptor. */ void libxfs_trans_del_item( struct xfs_log_item *lip) { list_del_init(&lip->li_desc->lid_trans); free(lip->li_desc); lip->li_desc = NULL; } /* * Roll from one trans in the sequence of PERMANENT transactions to * the next: permanent transactions are only flushed out when * committed with XFS_TRANS_RELEASE_LOG_RES, but we still want as soon * as possible to let chunks of it go to the log. So we commit the * chunk we've been working on and get a new transaction to continue. */ int libxfs_trans_roll( struct xfs_trans **tpp, struct xfs_inode *dp) { struct xfs_trans *trans; struct xfs_trans_res tres; int error; /* * Ensure that the inode is always logged. */ trans = *tpp; if (dp) xfs_trans_log_inode(trans, dp, XFS_ILOG_CORE); /* * Copy the critical parameters from one trans to the next. */ tres.tr_logres = trans->t_log_res; tres.tr_logcount = trans->t_log_count; *tpp = libxfs_trans_alloc(trans->t_mountp, trans->t_type); /* * Commit the current transaction. * If this commit failed, then it'd just unlock those items that * are marked to be released. That also means that a filesystem shutdown * is in progress. The caller takes the responsibility to cancel * the duplicate transaction that gets returned. */ error = xfs_trans_commit(trans); if (error) return error; trans = *tpp; /* * Reserve space in the log for th next transaction. * This also pushes items in the "AIL", the list of logged items, * out to disk if they are taking up space at the tail of the log * that we want to use. This requires that either nothing be locked * across this call, or that anything that is locked be logged in * the prior and the next transactions. */ tres.tr_logflags = XFS_TRANS_PERM_LOG_RES; error = xfs_trans_reserve(trans, &tres, 0, 0); /* * Ensure that the inode is in the new transaction and locked. */ if (error) return error; if (dp) xfs_trans_ijoin(trans, dp, 0); return 0; } xfs_trans_t * libxfs_trans_alloc( xfs_mount_t *mp, int type) { xfs_trans_t *ptr; if ((ptr = calloc(sizeof(xfs_trans_t), 1)) == NULL) { fprintf(stderr, _("%s: xact calloc failed (%d bytes): %s\n"), progname, (int)sizeof(xfs_trans_t), strerror(errno)); exit(1); } ptr->t_mountp = mp; ptr->t_type = type; INIT_LIST_HEAD(&ptr->t_items); #ifdef XACT_DEBUG fprintf(stderr, "allocated new transaction %p\n", ptr); #endif return ptr; } int libxfs_trans_reserve( struct xfs_trans *tp, struct xfs_trans_res *resp, uint blocks, uint rtextents) { xfs_sb_t *mpsb = &tp->t_mountp->m_sb; /* * Attempt to reserve the needed disk blocks by decrementing * the number needed from the number available. This will * fail if the count would go below zero. */ if (blocks > 0) { if (mpsb->sb_fdblocks < blocks) return -ENOSPC; } /* user space, don't need log/RT stuff (preserve the API though) */ return 0; } void libxfs_trans_cancel( xfs_trans_t *tp) { #ifdef XACT_DEBUG xfs_trans_t *otp = tp; #endif if (tp != NULL) { xfs_trans_free_items(tp); free(tp); tp = NULL; } #ifdef XACT_DEBUG fprintf(stderr, "## cancelled transaction %p\n", otp); #endif } int libxfs_trans_iget( xfs_mount_t *mp, xfs_trans_t *tp, xfs_ino_t ino, uint flags, uint lock_flags, xfs_inode_t **ipp) { int error; xfs_inode_t *ip; xfs_inode_log_item_t *iip; if (tp == NULL) return libxfs_iget(mp, tp, ino, lock_flags, ipp, 0); error = libxfs_iget(mp, tp, ino, lock_flags, &ip, 0); if (error) return error; ASSERT(ip != NULL); if (ip->i_itemp == NULL) xfs_inode_item_init(ip, mp); iip = ip->i_itemp; xfs_trans_add_item(tp, (xfs_log_item_t *)(iip)); /* initialize i_transp so we can find it incore */ ip->i_transp = tp; *ipp = ip; return 0; } void libxfs_trans_ijoin( xfs_trans_t *tp, xfs_inode_t *ip, uint lock_flags) { xfs_inode_log_item_t *iip; ASSERT(ip->i_transp == NULL); if (ip->i_itemp == NULL) xfs_inode_item_init(ip, ip->i_mount); iip = ip->i_itemp; ASSERT(iip->ili_flags == 0); ASSERT(iip->ili_inode != NULL); xfs_trans_add_item(tp, (xfs_log_item_t *)(iip)); ip->i_transp = tp; #ifdef XACT_DEBUG fprintf(stderr, "ijoin'd inode %llu, transaction %p\n", ip->i_ino, tp); #endif } void libxfs_trans_ijoin_ref( xfs_trans_t *tp, xfs_inode_t *ip, int lock_flags) { ASSERT(ip->i_transp == tp); ASSERT(ip->i_itemp != NULL); xfs_trans_ijoin(tp, ip, lock_flags); #ifdef XACT_DEBUG fprintf(stderr, "ijoin_ref'd inode %llu, transaction %p\n", ip->i_ino, tp); #endif } void libxfs_trans_inode_alloc_buf( xfs_trans_t *tp, xfs_buf_t *bp) { xfs_buf_log_item_t *bip; ASSERT(XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp); ASSERT(XFS_BUF_FSPRIVATE(bp, void *) != NULL); bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *); bip->bli_flags |= XFS_BLI_INODE_ALLOC_BUF; xfs_trans_buf_set_type(tp, bp, XFS_BLFT_DINO_BUF); } /* * This is called to mark the fields indicated in fieldmask as needing * to be logged when the transaction is committed. The inode must * already be associated with the given transaction. * * The values for fieldmask are defined in xfs_log_format.h. We always * log all of the core inode if any of it has changed, and we always log * all of the inline data/extents/b-tree root if any of them has changed. */ void xfs_trans_log_inode( xfs_trans_t *tp, xfs_inode_t *ip, uint flags) { ASSERT(ip->i_transp == tp); ASSERT(ip->i_itemp != NULL); #ifdef XACT_DEBUG fprintf(stderr, "dirtied inode %llu, transaction %p\n", ip->i_ino, tp); #endif tp->t_flags |= XFS_TRANS_DIRTY; ip->i_itemp->ili_item.li_desc->lid_flags |= XFS_LID_DIRTY; /* * Always OR in the bits from the ili_last_fields field. * This is to coordinate with the xfs_iflush() and xfs_iflush_done() * routines in the eventual clearing of the ilf_fields bits. * See the big comment in xfs_iflush() for an explanation of * this coordination mechanism. */ flags |= ip->i_itemp->ili_last_fields; ip->i_itemp->ili_fields |= flags; } /* * This is called to mark bytes first through last inclusive of the given * buffer as needing to be logged when the transaction is committed. * The buffer must already be associated with the given transaction. * * First and last are numbers relative to the beginning of this buffer, * so the first byte in the buffer is numbered 0 regardless of the * value of b_blkno. */ void libxfs_trans_log_buf( xfs_trans_t *tp, xfs_buf_t *bp, uint first, uint last) { xfs_buf_log_item_t *bip; ASSERT(XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp); ASSERT(XFS_BUF_FSPRIVATE(bp, void *) != NULL); ASSERT((first <= last) && (last < XFS_BUF_COUNT(bp))); #ifdef XACT_DEBUG fprintf(stderr, "dirtied buffer %p, transaction %p\n", bp, tp); #endif bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *); tp->t_flags |= XFS_TRANS_DIRTY; bip->bli_item.li_desc->lid_flags |= XFS_LID_DIRTY; xfs_buf_item_log(bip, first, last); } void libxfs_trans_brelse( xfs_trans_t *tp, xfs_buf_t *bp) { xfs_buf_log_item_t *bip; #ifdef XACT_DEBUG fprintf(stderr, "released buffer %p, transaction %p\n", bp, tp); #endif if (tp == NULL) { ASSERT(XFS_BUF_FSPRIVATE2(bp, void *) == NULL); libxfs_putbuf(bp); return; } ASSERT(XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp); bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *); ASSERT(bip->bli_item.li_type == XFS_LI_BUF); if (bip->bli_recur > 0) { bip->bli_recur--; return; } /* If dirty/stale, can't release till transaction committed */ if (bip->bli_flags & XFS_BLI_STALE) return; if (bip->bli_item.li_desc->lid_flags & XFS_LID_DIRTY) return; xfs_trans_del_item(&bip->bli_item); if (bip->bli_flags & XFS_BLI_HOLD) bip->bli_flags &= ~XFS_BLI_HOLD; XFS_BUF_SET_FSPRIVATE2(bp, NULL); libxfs_putbuf(bp); } void libxfs_trans_binval( xfs_trans_t *tp, xfs_buf_t *bp) { xfs_buf_log_item_t *bip; #ifdef XACT_DEBUG fprintf(stderr, "binval'd buffer %p, transaction %p\n", bp, tp); #endif ASSERT(XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp); ASSERT(XFS_BUF_FSPRIVATE(bp, void *) != NULL); bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *); if (bip->bli_flags & XFS_BLI_STALE) return; XFS_BUF_UNDELAYWRITE(bp); xfs_buf_stale(bp); bip->bli_flags |= XFS_BLI_STALE; bip->bli_flags &= ~XFS_BLI_DIRTY; bip->bli_format.blf_flags &= ~XFS_BLF_INODE_BUF; bip->bli_format.blf_flags |= XFS_BLF_CANCEL; bip->bli_item.li_desc->lid_flags |= XFS_LID_DIRTY; tp->t_flags |= XFS_TRANS_DIRTY; } void libxfs_trans_bjoin( xfs_trans_t *tp, xfs_buf_t *bp) { xfs_buf_log_item_t *bip; ASSERT(XFS_BUF_FSPRIVATE2(bp, void *) == NULL); #ifdef XACT_DEBUG fprintf(stderr, "bjoin'd buffer %p, transaction %p\n", bp, tp); #endif xfs_buf_item_init(bp, tp->t_mountp); bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *); xfs_trans_add_item(tp, (xfs_log_item_t *)bip); XFS_BUF_SET_FSPRIVATE2(bp, tp); } void libxfs_trans_bhold( xfs_trans_t *tp, xfs_buf_t *bp) { xfs_buf_log_item_t *bip; ASSERT(XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp); ASSERT(XFS_BUF_FSPRIVATE(bp, void *) != NULL); #ifdef XACT_DEBUG fprintf(stderr, "bhold'd buffer %p, transaction %p\n", bp, tp); #endif bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *); bip->bli_flags |= XFS_BLI_HOLD; } xfs_buf_t * libxfs_trans_get_buf_map( xfs_trans_t *tp, struct xfs_buftarg *btp, struct xfs_buf_map *map, int nmaps, uint f) { xfs_buf_t *bp; xfs_buf_log_item_t *bip; if (tp == NULL) return libxfs_getbuf_map(btp, map, nmaps, 0); bp = xfs_trans_buf_item_match(tp, btp, map, nmaps); if (bp != NULL) { ASSERT(XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp); bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *); ASSERT(bip != NULL); bip->bli_recur++; return bp; } bp = libxfs_getbuf_map(btp, map, nmaps, 0); if (bp == NULL) return NULL; #ifdef XACT_DEBUG fprintf(stderr, "trans_get_buf buffer %p, transaction %p\n", bp, tp); #endif xfs_buf_item_init(bp, tp->t_mountp); bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t*); bip->bli_recur = 0; xfs_trans_add_item(tp, (xfs_log_item_t *)bip); /* initialize b_fsprivate2 so we can find it incore */ XFS_BUF_SET_FSPRIVATE2(bp, tp); return bp; } xfs_buf_t * libxfs_trans_getsb( xfs_trans_t *tp, xfs_mount_t *mp, int flags) { xfs_buf_t *bp; xfs_buf_log_item_t *bip; int len = XFS_FSS_TO_BB(mp, 1); DEFINE_SINGLE_BUF_MAP(map, XFS_SB_DADDR, len); if (tp == NULL) return libxfs_getsb(mp, flags); bp = xfs_trans_buf_item_match(tp, mp->m_dev, &map, 1); if (bp != NULL) { ASSERT(XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp); bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *); ASSERT(bip != NULL); bip->bli_recur++; return bp; } bp = libxfs_getsb(mp, flags); #ifdef XACT_DEBUG fprintf(stderr, "trans_get_sb buffer %p, transaction %p\n", bp, tp); #endif xfs_buf_item_init(bp, mp); bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t*); bip->bli_recur = 0; xfs_trans_add_item(tp, (xfs_log_item_t *)bip); /* initialize b_fsprivate2 so we can find it incore */ XFS_BUF_SET_FSPRIVATE2(bp, tp); return bp; } int libxfs_trans_read_buf_map( xfs_mount_t *mp, xfs_trans_t *tp, struct xfs_buftarg *btp, struct xfs_buf_map *map, int nmaps, uint flags, xfs_buf_t **bpp, const struct xfs_buf_ops *ops) { xfs_buf_t *bp; xfs_buf_log_item_t *bip; int error; *bpp = NULL; if (tp == NULL) { bp = libxfs_readbuf_map(btp, map, nmaps, flags, ops); if (!bp) { return (flags & XBF_TRYLOCK) ? -EAGAIN : -ENOMEM; } if (bp->b_error) goto out_relse; goto done; } bp = xfs_trans_buf_item_match(tp, btp, map, nmaps); if (bp != NULL) { ASSERT(XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp); ASSERT(XFS_BUF_FSPRIVATE(bp, void *) != NULL); bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t*); bip->bli_recur++; goto done; } bp = libxfs_readbuf_map(btp, map, nmaps, flags, ops); if (!bp) { return (flags & XBF_TRYLOCK) ? -EAGAIN : -ENOMEM; } if (bp->b_error) goto out_relse; #ifdef XACT_DEBUG fprintf(stderr, "trans_read_buf buffer %p, transaction %p\n", bp, tp); #endif xfs_buf_item_init(bp, tp->t_mountp); bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *); bip->bli_recur = 0; xfs_trans_add_item(tp, (xfs_log_item_t *)bip); /* initialise b_fsprivate2 so we can find it incore */ XFS_BUF_SET_FSPRIVATE2(bp, tp); done: *bpp = bp; return 0; out_relse: error = bp->b_error; xfs_buf_relse(bp); return error; } /* * Record the indicated change to the given field for application * to the file system's superblock when the transaction commits. * For now, just store the change in the transaction structure. * Mark the transaction structure to indicate that the superblock * needs to be updated before committing. * * Originally derived from xfs_trans_mod_sb(). */ void libxfs_trans_mod_sb( xfs_trans_t *tp, uint field, long delta) { switch (field) { case XFS_TRANS_SB_RES_FDBLOCKS: return; case XFS_TRANS_SB_FDBLOCKS: tp->t_fdblocks_delta += delta; break; case XFS_TRANS_SB_ICOUNT: ASSERT(delta > 0); tp->t_icount_delta += delta; break; case XFS_TRANS_SB_IFREE: tp->t_ifree_delta += delta; break; case XFS_TRANS_SB_FREXTENTS: tp->t_frextents_delta += delta; break; default: ASSERT(0); return; } tp->t_flags |= (XFS_TRANS_SB_DIRTY | XFS_TRANS_DIRTY); } /* * Transaction commital code follows (i.e. write to disk in libxfs) */ static void inode_item_done( xfs_inode_log_item_t *iip) { xfs_dinode_t *dip; xfs_inode_t *ip; xfs_mount_t *mp; xfs_buf_t *bp; int error; ip = iip->ili_inode; mp = iip->ili_item.li_mountp; ASSERT(ip != NULL); if (!(iip->ili_fields & XFS_ILOG_ALL)) { ip->i_transp = NULL; /* disassociate from transaction */ iip->ili_flags = 0; /* reset all flags */ return; } /* * Get the buffer containing the on-disk inode. */ error = xfs_imap_to_bp(mp, NULL, &ip->i_imap, &dip, &bp, 0, 0); if (error) { fprintf(stderr, _("%s: warning - imap_to_bp failed (%d)\n"), progname, error); return; } XFS_BUF_SET_FSPRIVATE(bp, iip); error = libxfs_iflush_int(ip, bp); if (error) { fprintf(stderr, _("%s: warning - iflush_int failed (%d)\n"), progname, error); return; } ip->i_transp = NULL; /* disassociate from transaction */ XFS_BUF_SET_FSPRIVATE(bp, NULL); /* remove log item */ XFS_BUF_SET_FSPRIVATE2(bp, NULL); /* remove xact ptr */ libxfs_writebuf(bp, 0); #ifdef XACT_DEBUG fprintf(stderr, "flushing dirty inode %llu, buffer %p\n", ip->i_ino, bp); #endif } static void buf_item_done( xfs_buf_log_item_t *bip) { xfs_buf_t *bp; int hold; extern kmem_zone_t *xfs_buf_item_zone; bp = bip->bli_buf; ASSERT(bp != NULL); XFS_BUF_SET_FSPRIVATE(bp, NULL); /* remove log item */ XFS_BUF_SET_FSPRIVATE2(bp, NULL); /* remove xact ptr */ hold = (bip->bli_flags & XFS_BLI_HOLD); if (bip->bli_flags & XFS_BLI_DIRTY) { #ifdef XACT_DEBUG fprintf(stderr, "flushing/staling buffer %p (hold=%d)\n", bp, hold); #endif libxfs_writebuf_int(bp, 0); } if (hold) bip->bli_flags &= ~XFS_BLI_HOLD; else libxfs_putbuf(bp); /* release the buf item */ kmem_zone_free(xfs_buf_item_zone, bip); } static void trans_committed( xfs_trans_t *tp) { struct xfs_log_item_desc *lidp, *next; list_for_each_entry_safe(lidp, next, &tp->t_items, lid_trans) { struct xfs_log_item *lip = lidp->lid_item; xfs_trans_del_item(lip); if (lip->li_type == XFS_LI_BUF) buf_item_done((xfs_buf_log_item_t *)lip); else if (lip->li_type == XFS_LI_INODE) inode_item_done((xfs_inode_log_item_t *)lip); else { fprintf(stderr, _("%s: unrecognised log item type\n"), progname); ASSERT(0); } } } static void buf_item_unlock( xfs_buf_log_item_t *bip) { xfs_buf_t *bp = bip->bli_buf; uint hold; /* Clear the buffer's association with this transaction. */ XFS_BUF_SET_FSPRIVATE2(bip->bli_buf, NULL); hold = bip->bli_flags & XFS_BLI_HOLD; bip->bli_flags &= ~XFS_BLI_HOLD; if (!hold) libxfs_putbuf(bp); } static void inode_item_unlock( xfs_inode_log_item_t *iip) { xfs_inode_t *ip = iip->ili_inode; /* Clear the transaction pointer in the inode. */ ip->i_transp = NULL; iip->ili_flags = 0; } /* * Unlock all of the items of a transaction and free all the descriptors * of that transaction. */ static void xfs_trans_free_items( struct xfs_trans *tp) { struct xfs_log_item_desc *lidp, *next; list_for_each_entry_safe(lidp, next, &tp->t_items, lid_trans) { struct xfs_log_item *lip = lidp->lid_item; xfs_trans_del_item(lip); if (lip->li_type == XFS_LI_BUF) buf_item_unlock((xfs_buf_log_item_t *)lip); else if (lip->li_type == XFS_LI_INODE) inode_item_unlock((xfs_inode_log_item_t *)lip); else { fprintf(stderr, _("%s: unrecognised log item type\n"), progname); ASSERT(0); } } } /* * Commit the changes represented by this transaction */ int libxfs_trans_commit( xfs_trans_t *tp) { xfs_sb_t *sbp; if (tp == NULL) return 0; if (!(tp->t_flags & XFS_TRANS_DIRTY)) { #ifdef XACT_DEBUG fprintf(stderr, "committed clean transaction %p\n", tp); #endif xfs_trans_free_items(tp); free(tp); tp = NULL; return 0; } if (tp->t_flags & XFS_TRANS_SB_DIRTY) { sbp = &(tp->t_mountp->m_sb); if (tp->t_icount_delta) sbp->sb_icount += tp->t_icount_delta; if (tp->t_ifree_delta) sbp->sb_ifree += tp->t_ifree_delta; if (tp->t_fdblocks_delta) sbp->sb_fdblocks += tp->t_fdblocks_delta; if (tp->t_frextents_delta) sbp->sb_frextents += tp->t_frextents_delta; xfs_log_sb(tp); } #ifdef XACT_DEBUG fprintf(stderr, "committing dirty transaction %p\n", tp); #endif trans_committed(tp); /* That's it for the transaction structure. Free it. */ free(tp); tp = NULL; return 0; } partclone-0.2.86/src/xfs/util.c000066400000000000000000000461211262102574200163130ustar00rootroot00000000000000/* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "libxfs_priv.h" #include "init.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_mount.h" #include "xfs_inode_buf.h" #include "xfs_inode_fork.h" #include "xfs_inode.h" #include "xfs_trans.h" #include "xfs_bmap.h" #include "xfs_bmap_btree.h" #include "xfs_trans_space.h" #include "xfs_ialloc.h" #include "xfs_alloc.h" /* * Calculate the worst case log unit reservation for a given superblock * configuration. Copied and munged from the kernel code, and assumes a * worse case header usage (maximum log buffer sizes) */ int xfs_log_calc_unit_res( struct xfs_mount *mp, int unit_bytes) { int iclog_space; int iclog_header_size; int iclog_size; uint num_headers; if (xfs_sb_version_haslogv2(&mp->m_sb)) { iclog_size = XLOG_MAX_RECORD_BSIZE; iclog_header_size = BBTOB(iclog_size / XLOG_HEADER_CYCLE_SIZE); } else { iclog_size = XLOG_BIG_RECORD_BSIZE; iclog_header_size = BBSIZE; } /* * Permanent reservations have up to 'cnt'-1 active log operations * in the log. A unit in this case is the amount of space for one * of these log operations. Normal reservations have a cnt of 1 * and their unit amount is the total amount of space required. * * The following lines of code account for non-transaction data * which occupy space in the on-disk log. * * Normal form of a transaction is: * ... * and then there are LR hdrs, split-recs and roundoff at end of syncs. * * We need to account for all the leadup data and trailer data * around the transaction data. * And then we need to account for the worst case in terms of using * more space. * The worst case will happen if: * - the placement of the transaction happens to be such that the * roundoff is at its maximum * - the transaction data is synced before the commit record is synced * i.e. | * Therefore the commit record is in its own Log Record. * This can happen as the commit record is called with its * own region to xlog_write(). * This then means that in the worst case, roundoff can happen for * the commit-rec as well. * The commit-rec is smaller than padding in this scenario and so it is * not added separately. */ /* for trans header */ unit_bytes += sizeof(xlog_op_header_t); unit_bytes += sizeof(xfs_trans_header_t); /* for start-rec */ unit_bytes += sizeof(xlog_op_header_t); /* * for LR headers - the space for data in an iclog is the size minus * the space used for the headers. If we use the iclog size, then we * undercalculate the number of headers required. * * Furthermore - the addition of op headers for split-recs might * increase the space required enough to require more log and op * headers, so take that into account too. * * IMPORTANT: This reservation makes the assumption that if this * transaction is the first in an iclog and hence has the LR headers * accounted to it, then the remaining space in the iclog is * exclusively for this transaction. i.e. if the transaction is larger * than the iclog, it will be the only thing in that iclog. * Fundamentally, this means we must pass the entire log vector to * xlog_write to guarantee this. */ iclog_space = iclog_size - iclog_header_size; num_headers = howmany(unit_bytes, iclog_space); /* for split-recs - ophdrs added when data split over LRs */ unit_bytes += sizeof(xlog_op_header_t) * num_headers; /* add extra header reservations if we overrun */ while (!num_headers || howmany(unit_bytes, iclog_space) > num_headers) { unit_bytes += sizeof(xlog_op_header_t); num_headers++; } unit_bytes += iclog_header_size * num_headers; /* for commit-rec LR header - note: padding will subsume the ophdr */ unit_bytes += iclog_header_size; /* for roundoff padding for transaction data and one for commit record */ if (xfs_sb_version_haslogv2(&mp->m_sb) && mp->m_sb.sb_logsunit > 1) { /* log su roundoff */ unit_bytes += 2 * mp->m_sb.sb_logsunit; } else { /* BB roundoff */ unit_bytes += 2 * BBSIZE; } return unit_bytes; } /* * Change the requested timestamp in the given inode. * * This was once shared with the kernel, but has diverged to the point * where it's no longer worth the hassle of maintaining common code. */ void libxfs_trans_ichgtime( struct xfs_trans *tp, struct xfs_inode *ip, int flags) { struct timespec tv; struct timeval stv; gettimeofday(&stv, (struct timezone *)0); tv.tv_sec = stv.tv_sec; tv.tv_nsec = stv.tv_usec * 1000; if (flags & XFS_ICHGTIME_MOD) { ip->i_d.di_mtime.t_sec = (__int32_t)tv.tv_sec; ip->i_d.di_mtime.t_nsec = (__int32_t)tv.tv_nsec; } if (flags & XFS_ICHGTIME_CHG) { ip->i_d.di_ctime.t_sec = (__int32_t)tv.tv_sec; ip->i_d.di_ctime.t_nsec = (__int32_t)tv.tv_nsec; } if (flags & XFS_ICHGTIME_CREATE) { ip->i_d.di_crtime.t_sec = (__int32_t)tv.tv_sec; ip->i_d.di_crtime.t_nsec = (__int32_t)tv.tv_nsec; } } /* * Allocate an inode on disk and return a copy of its in-core version. * Set mode, nlink, and rdev appropriately within the inode. * The uid and gid for the inode are set according to the contents of * the given cred structure. * * This was once shared with the kernel, but has diverged to the point * where it's no longer worth the hassle of maintaining common code. */ int libxfs_ialloc( xfs_trans_t *tp, xfs_inode_t *pip, mode_t mode, nlink_t nlink, xfs_dev_t rdev, struct cred *cr, struct fsxattr *fsx, int okalloc, xfs_buf_t **ialloc_context, xfs_inode_t **ipp) { xfs_ino_t ino; xfs_inode_t *ip; uint flags; int error; /* * Call the space management code to pick * the on-disk inode to be allocated. */ error = xfs_dialloc(tp, pip ? pip->i_ino : 0, mode, okalloc, ialloc_context, &ino); if (error != 0) return error; if (*ialloc_context || ino == NULLFSINO) { *ipp = NULL; return 0; } ASSERT(*ialloc_context == NULL); error = xfs_trans_iget(tp->t_mountp, tp, ino, 0, 0, &ip); if (error != 0) return error; ASSERT(ip != NULL); ip->i_d.di_mode = (__uint16_t)mode; ip->i_d.di_onlink = 0; ip->i_d.di_nlink = nlink; ASSERT(ip->i_d.di_nlink == nlink); ip->i_d.di_uid = cr->cr_uid; ip->i_d.di_gid = cr->cr_gid; xfs_set_projid(&ip->i_d, pip ? 0 : fsx->fsx_projid); memset(&(ip->i_d.di_pad[0]), 0, sizeof(ip->i_d.di_pad)); xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_CHG | XFS_ICHGTIME_MOD); /* * We only support filesystems that understand v2 format inodes. So if * this is currently an old format inode, then change the inode version * number now. This way we only do the conversion here rather than here * and in the flush/logging code. */ if (ip->i_d.di_version == 1) { ip->i_d.di_version = 2; /* * old link count, projid_lo/hi field, pad field * already zeroed */ } if (pip && (pip->i_d.di_mode & S_ISGID)) { ip->i_d.di_gid = pip->i_d.di_gid; if ((pip->i_d.di_mode & S_ISGID) && (mode & S_IFMT) == S_IFDIR) ip->i_d.di_mode |= S_ISGID; } ip->i_d.di_size = 0; ip->i_d.di_nextents = 0; ASSERT(ip->i_d.di_nblocks == 0); /* * di_gen will have been taken care of in xfs_iread. */ ip->i_d.di_extsize = pip ? 0 : fsx->fsx_extsize; ip->i_d.di_dmevmask = 0; ip->i_d.di_dmstate = 0; ip->i_d.di_flags = pip ? 0 : fsx->fsx_xflags; if (ip->i_d.di_version == 3) { ASSERT(ip->i_d.di_ino == ino); ASSERT(uuid_equal(&ip->i_d.di_uuid, &mp->m_sb.sb_meta_uuid)); ip->i_d.di_crc = 0; ip->i_d.di_changecount = 1; ip->i_d.di_lsn = 0; ip->i_d.di_flags2 = 0; memset(&(ip->i_d.di_pad2[0]), 0, sizeof(ip->i_d.di_pad2)); ip->i_d.di_crtime = ip->i_d.di_mtime; } flags = XFS_ILOG_CORE; switch (mode & S_IFMT) { case S_IFIFO: case S_IFSOCK: /* doesn't make sense to set an rdev for these */ rdev = 0; /* FALLTHROUGH */ case S_IFCHR: case S_IFBLK: ip->i_d.di_format = XFS_DINODE_FMT_DEV; ip->i_df.if_u2.if_rdev = rdev; flags |= XFS_ILOG_DEV; break; case S_IFREG: case S_IFDIR: if (pip && (pip->i_d.di_flags & XFS_DIFLAG_ANY)) { uint di_flags = 0; if ((mode & S_IFMT) == S_IFDIR) { if (pip->i_d.di_flags & XFS_DIFLAG_RTINHERIT) di_flags |= XFS_DIFLAG_RTINHERIT; if (pip->i_d.di_flags & XFS_DIFLAG_EXTSZINHERIT) { di_flags |= XFS_DIFLAG_EXTSZINHERIT; ip->i_d.di_extsize = pip->i_d.di_extsize; } } else { if (pip->i_d.di_flags & XFS_DIFLAG_RTINHERIT) { di_flags |= XFS_DIFLAG_REALTIME; } if (pip->i_d.di_flags & XFS_DIFLAG_EXTSZINHERIT) { di_flags |= XFS_DIFLAG_EXTSIZE; ip->i_d.di_extsize = pip->i_d.di_extsize; } } if (pip->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) di_flags |= XFS_DIFLAG_PROJINHERIT; ip->i_d.di_flags |= di_flags; } /* FALLTHROUGH */ case S_IFLNK: ip->i_d.di_format = XFS_DINODE_FMT_EXTENTS; ip->i_df.if_flags = XFS_IFEXTENTS; ip->i_df.if_bytes = ip->i_df.if_real_bytes = 0; ip->i_df.if_u1.if_extents = NULL; break; default: ASSERT(0); } /* Attribute fork settings for new inode. */ ip->i_d.di_aformat = XFS_DINODE_FMT_EXTENTS; ip->i_d.di_anextents = 0; /* * set up the inode ops structure that the libxfs code relies on */ if (S_ISDIR(ip->i_d.di_mode)) ip->d_ops = ip->i_mount->m_dir_inode_ops; else ip->d_ops = ip->i_mount->m_nondir_inode_ops; /* * Log the new values stuffed into the inode. */ xfs_trans_log_inode(tp, ip, flags); *ipp = ip; return 0; } void libxfs_iprint( xfs_inode_t *ip) { xfs_icdinode_t *dip; xfs_bmbt_rec_host_t *ep; xfs_extnum_t i; xfs_extnum_t nextents; printf("Inode %lx\n", (unsigned long)ip); printf(" i_ino %llx\n", (unsigned long long)ip->i_ino); if (ip->i_df.if_flags & XFS_IFEXTENTS) printf("EXTENTS "); printf("\n"); printf(" i_df.if_bytes %d\n", ip->i_df.if_bytes); printf(" i_df.if_u1.if_extents/if_data %lx\n", (unsigned long)ip->i_df.if_u1.if_extents); if (ip->i_df.if_flags & XFS_IFEXTENTS) { nextents = ip->i_df.if_bytes / (uint)sizeof(*ep); for (ep = ip->i_df.if_u1.if_extents, i = 0; i < nextents; i++, ep++) { xfs_bmbt_irec_t rec; xfs_bmbt_get_all(ep, &rec); printf("\t%d: startoff %llu, startblock 0x%llx," " blockcount %llu, state %d\n", i, (unsigned long long)rec.br_startoff, (unsigned long long)rec.br_startblock, (unsigned long long)rec.br_blockcount, (int)rec.br_state); } } printf(" i_df.if_broot %lx\n", (unsigned long)ip->i_df.if_broot); printf(" i_df.if_broot_bytes %x\n", ip->i_df.if_broot_bytes); dip = &ip->i_d; printf("\nOn disk portion\n"); printf(" di_magic %x\n", dip->di_magic); printf(" di_mode %o\n", dip->di_mode); printf(" di_version %x\n", (uint)dip->di_version); switch (ip->i_d.di_format) { case XFS_DINODE_FMT_LOCAL: printf(" Inline inode\n"); break; case XFS_DINODE_FMT_EXTENTS: printf(" Extents inode\n"); break; case XFS_DINODE_FMT_BTREE: printf(" B-tree inode\n"); break; default: printf(" Other inode\n"); break; } printf(" di_nlink %x\n", dip->di_nlink); printf(" di_uid %d\n", dip->di_uid); printf(" di_gid %d\n", dip->di_gid); printf(" di_nextents %d\n", dip->di_nextents); printf(" di_size %llu\n", (unsigned long long)dip->di_size); printf(" di_gen %x\n", dip->di_gen); printf(" di_extsize %d\n", dip->di_extsize); printf(" di_flags %x\n", dip->di_flags); printf(" di_nblocks %llu\n", (unsigned long long)dip->di_nblocks); } /* * Writes a modified inode's changes out to the inode's on disk home. * Originally based on xfs_iflush_int() from xfs_inode.c in the kernel. */ int libxfs_iflush_int(xfs_inode_t *ip, xfs_buf_t *bp) { xfs_inode_log_item_t *iip; xfs_dinode_t *dip; xfs_mount_t *mp; ASSERT(XFS_BUF_FSPRIVATE(bp, void *) != NULL); ASSERT(ip->i_d.di_format != XFS_DINODE_FMT_BTREE || ip->i_d.di_nextents > ip->i_df.if_ext_max); ASSERT(ip->i_d.di_version > 1); iip = ip->i_itemp; mp = ip->i_mount; /* set *dip = inode's place in the buffer */ dip = xfs_buf_offset(bp, ip->i_imap.im_boffset); ASSERT(ip->i_d.di_magic == XFS_DINODE_MAGIC); if ((ip->i_d.di_mode & S_IFMT) == S_IFREG) { ASSERT( (ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS) || (ip->i_d.di_format == XFS_DINODE_FMT_BTREE) ); } else if ((ip->i_d.di_mode & S_IFMT) == S_IFDIR) { ASSERT( (ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS) || (ip->i_d.di_format == XFS_DINODE_FMT_BTREE) || (ip->i_d.di_format == XFS_DINODE_FMT_LOCAL) ); } ASSERT(ip->i_d.di_nextents+ip->i_d.di_anextents <= ip->i_d.di_nblocks); ASSERT(ip->i_d.di_forkoff <= mp->m_sb.sb_inodesize); /* bump the change count on v3 inodes */ if (ip->i_d.di_version == 3) ip->i_d.di_changecount++; /* * Copy the dirty parts of the inode into the on-disk * inode. We always copy out the core of the inode, * because if the inode is dirty at all the core must * be. */ xfs_dinode_to_disk(dip, &ip->i_d); xfs_iflush_fork(ip, dip, iip, XFS_DATA_FORK); if (XFS_IFORK_Q(ip)) xfs_iflush_fork(ip, dip, iip, XFS_ATTR_FORK); /* update the lsn in the on disk inode if required */ if (ip->i_d.di_version == 3) dip->di_lsn = cpu_to_be64(iip->ili_item.li_lsn); /* generate the checksum. */ xfs_dinode_calc_crc(mp, dip); return 0; } int libxfs_mod_incore_sb( struct xfs_mount *mp, int field, int64_t delta, int rsvd) { long long lcounter; /* long counter for 64 bit fields */ switch (field) { case XFS_TRANS_SB_FDBLOCKS: lcounter = (long long)mp->m_sb.sb_fdblocks; lcounter += delta; if (lcounter < 0) return -ENOSPC; mp->m_sb.sb_fdblocks = lcounter; return 0; default: ASSERT(0); return -EINVAL; } } int libxfs_bmap_finish( xfs_trans_t **tp, xfs_bmap_free_t *flist, int *committed) { xfs_bmap_free_item_t *free; /* free extent list item */ xfs_bmap_free_item_t *next; /* next item on free list */ int error; if (flist->xbf_count == 0) { *committed = 0; return 0; } for (free = flist->xbf_first; free != NULL; free = next) { next = free->xbfi_next; if ((error = xfs_free_extent(*tp, free->xbfi_startblock, free->xbfi_blockcount))) return error; xfs_bmap_del_free(flist, NULL, free); } *committed = 0; return 0; } /* * This routine allocates disk space for the given file. * Originally derived from xfs_alloc_file_space(). */ int libxfs_alloc_file_space( xfs_inode_t *ip, xfs_off_t offset, xfs_off_t len, int alloc_type, int attr_flags) { xfs_mount_t *mp; xfs_off_t count; xfs_filblks_t datablocks; xfs_filblks_t allocated_fsb; xfs_filblks_t allocatesize_fsb; xfs_fsblock_t firstfsb; xfs_bmap_free_t free_list; xfs_bmbt_irec_t *imapp; xfs_bmbt_irec_t imaps[1]; int reccount; uint resblks; xfs_fileoff_t startoffset_fsb; xfs_trans_t *tp; int xfs_bmapi_flags; int committed; int error; if (len <= 0) return -EINVAL; count = len; error = 0; imapp = &imaps[0]; reccount = 1; xfs_bmapi_flags = alloc_type ? XFS_BMAPI_PREALLOC : 0; mp = ip->i_mount; startoffset_fsb = XFS_B_TO_FSBT(mp, offset); allocatesize_fsb = XFS_B_TO_FSB(mp, count); /* allocate file space until done or until there is an error */ while (allocatesize_fsb && !error) { datablocks = allocatesize_fsb; tp = xfs_trans_alloc(mp, XFS_TRANS_DIOSTRAT); resblks = (uint)XFS_DIOSTRAT_SPACE_RES(mp, datablocks); error = xfs_trans_reserve(tp, &M_RES(mp)->tr_write, resblks, 0); /* * Check for running out of space */ if (error) { /* * Free the transaction structure. */ ASSERT(error == -ENOSPC); xfs_trans_cancel(tp); break; } xfs_trans_ijoin(tp, ip, 0); xfs_bmap_init(&free_list, &firstfsb); error = xfs_bmapi_write(tp, ip, startoffset_fsb, allocatesize_fsb, xfs_bmapi_flags, &firstfsb, 0, imapp, &reccount, &free_list); if (error) goto error0; /* complete the transaction */ error = xfs_bmap_finish(&tp, &free_list, &committed); if (error) goto error0; error = xfs_trans_commit(tp); if (error) break; allocated_fsb = imapp->br_blockcount; if (reccount == 0) return -ENOSPC; startoffset_fsb += allocated_fsb; allocatesize_fsb -= allocated_fsb; } return error; error0: /* Cancel bmap, cancel trans */ xfs_bmap_cancel(&free_list); xfs_trans_cancel(tp); return error; } unsigned int libxfs_log2_roundup(unsigned int i) { unsigned int rval; for (rval = 0; rval < NBBY * sizeof(i); rval++) { if ((1 << rval) >= i) break; } return rval; } /* * Wrapper around call to libxfs_ialloc. Takes care of committing and * allocating a new transaction as needed. * * Originally there were two copies of this code - one in mkfs, the * other in repair - now there is just the one. */ int libxfs_inode_alloc( xfs_trans_t **tp, xfs_inode_t *pip, mode_t mode, nlink_t nlink, xfs_dev_t rdev, struct cred *cr, struct fsxattr *fsx, xfs_inode_t **ipp) { xfs_buf_t *ialloc_context; xfs_inode_t *ip; int error; ialloc_context = (xfs_buf_t *)0; error = libxfs_ialloc(*tp, pip, mode, nlink, rdev, cr, fsx, 1, &ialloc_context, &ip); if (error) { *ipp = NULL; return error; } if (!ialloc_context && !ip) { *ipp = NULL; return -ENOSPC; } if (ialloc_context) { xfs_trans_bhold(*tp, ialloc_context); error = xfs_trans_roll(tp, NULL); if (error) { fprintf(stderr, _("%s: cannot duplicate transaction: %s\n"), progname, strerror(error)); exit(1); } xfs_trans_bjoin(*tp, ialloc_context); error = libxfs_ialloc(*tp, pip, mode, nlink, rdev, cr, fsx, 1, &ialloc_context, &ip); if (!ip) error = -ENOSPC; if (error) return error; } *ipp = ip; return error; } /* * Userspace versions of common diagnostic routines (varargs fun). */ void libxfs_fs_repair_cmn_err(int level, xfs_mount_t *mp, char *fmt, ...) { va_list ap; va_start(ap, fmt); vfprintf(stderr, fmt, ap); fprintf(stderr, " This is a bug.\n"); fprintf(stderr, "%s version \n", progname); fprintf(stderr, "Please capture the filesystem metadata with " "xfs_metadump and\nreport it to xfs@oss.sgi.com.\n"); va_end(ap); } void libxfs_fs_cmn_err(int level, xfs_mount_t *mp, char *fmt, ...) { va_list ap; va_start(ap, fmt); vfprintf(stderr, fmt, ap); fputs("\n", stderr); va_end(ap); } void cmn_err(int level, char *fmt, ...) { va_list ap; va_start(ap, fmt); vfprintf(stderr, fmt, ap); fputs("\n", stderr); va_end(ap); } /* * Warnings specifically for verifier errors. Differentiate CRC vs. invalid * values, and omit the stack trace unless the error level is tuned high. */ void xfs_verifier_error( struct xfs_buf *bp) { xfs_alert(NULL, "Metadata %s detected at block 0x%llx/0x%x", bp->b_error == -EFSBADCRC ? "CRC error" : "corruption", bp->b_bn, BBTOB(bp->b_length)); } partclone-0.2.86/src/xfs/xfs.h000066400000000000000000000036571262102574200161520ustar00rootroot00000000000000/* * Copyright (c) 2005 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2.1 of the GNU Lesser General Public License * as published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * * Further, this software is distributed without any warranty that it is * free of the rightful claim of any third person regarding infringement * or the like. Any license provided herein, whether implied or * otherwise, applies only to this software file. Patent licenses, if * any, provided herein do not apply to combinations of this program with * other software, or any other product whatsoever. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, write the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, * USA. * * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, * Mountain View, CA 94043, or: * * http://www.sgi.com * * For further information regarding this notice, see: * * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ #ifndef __XFS_H__ #define __XFS_H__ #if defined(__linux__) #include #elif defined(__FreeBSD__) #include #elif defined(__FreeBSD_kernel__) #include #elif defined(__APPLE__) #include #elif defined(__sgi__) || defined(__sgi) #include #else # error unknown platform... have fun porting! #endif #ifdef DEBUG # define ASSERT(EX) assert(EX) #else # define ASSERT(EX) ((void) 0) #endif /* * sparse kernel source annotations */ #ifndef __user #define __user #endif #include #include #endif /* __XFS_H__ */ partclone-0.2.86/src/xfs/xfs_alloc.c000066400000000000000000002236431262102574200173160ustar00rootroot00000000000000/* * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_shared.h" #include "xfs_trans_resv.h" #include "xfs_bit.h" #include "xfs_sb.h" #include "xfs_mount.h" #include "xfs_inode.h" #include "xfs_btree.h" #include "xfs_alloc_btree.h" #include "xfs_alloc.h" #include "xfs_cksum.h" #include "xfs_trace.h" #include "xfs_trans.h" struct workqueue_struct *xfs_alloc_wq; #define XFS_ABSDIFF(a,b) (((a) <= (b)) ? ((b) - (a)) : ((a) - (b))) #define XFSA_FIXUP_BNO_OK 1 #define XFSA_FIXUP_CNT_OK 2 STATIC int xfs_alloc_ag_vextent_exact(xfs_alloc_arg_t *); STATIC int xfs_alloc_ag_vextent_near(xfs_alloc_arg_t *); STATIC int xfs_alloc_ag_vextent_size(xfs_alloc_arg_t *); STATIC int xfs_alloc_ag_vextent_small(xfs_alloc_arg_t *, xfs_btree_cur_t *, xfs_agblock_t *, xfs_extlen_t *, int *); /* * Lookup the record equal to [bno, len] in the btree given by cur. */ STATIC int /* error */ xfs_alloc_lookup_eq( struct xfs_btree_cur *cur, /* btree cursor */ xfs_agblock_t bno, /* starting block of extent */ xfs_extlen_t len, /* length of extent */ int *stat) /* success/failure */ { cur->bc_rec.a.ar_startblock = bno; cur->bc_rec.a.ar_blockcount = len; return xfs_btree_lookup(cur, XFS_LOOKUP_EQ, stat); } /* * Lookup the first record greater than or equal to [bno, len] * in the btree given by cur. */ int /* error */ xfs_alloc_lookup_ge( struct xfs_btree_cur *cur, /* btree cursor */ xfs_agblock_t bno, /* starting block of extent */ xfs_extlen_t len, /* length of extent */ int *stat) /* success/failure */ { cur->bc_rec.a.ar_startblock = bno; cur->bc_rec.a.ar_blockcount = len; return xfs_btree_lookup(cur, XFS_LOOKUP_GE, stat); } /* * Lookup the first record less than or equal to [bno, len] * in the btree given by cur. */ int /* error */ xfs_alloc_lookup_le( struct xfs_btree_cur *cur, /* btree cursor */ xfs_agblock_t bno, /* starting block of extent */ xfs_extlen_t len, /* length of extent */ int *stat) /* success/failure */ { cur->bc_rec.a.ar_startblock = bno; cur->bc_rec.a.ar_blockcount = len; return xfs_btree_lookup(cur, XFS_LOOKUP_LE, stat); } /* * Update the record referred to by cur to the value given * by [bno, len]. * This either works (return 0) or gets an EFSCORRUPTED error. */ STATIC int /* error */ xfs_alloc_update( struct xfs_btree_cur *cur, /* btree cursor */ xfs_agblock_t bno, /* starting block of extent */ xfs_extlen_t len) /* length of extent */ { union xfs_btree_rec rec; rec.alloc.ar_startblock = cpu_to_be32(bno); rec.alloc.ar_blockcount = cpu_to_be32(len); return xfs_btree_update(cur, &rec); } /* * Get the data from the pointed-to record. */ int /* error */ xfs_alloc_get_rec( struct xfs_btree_cur *cur, /* btree cursor */ xfs_agblock_t *bno, /* output: starting block of extent */ xfs_extlen_t *len, /* output: length of extent */ int *stat) /* output: success/failure */ { union xfs_btree_rec *rec; int error; error = xfs_btree_get_rec(cur, &rec, stat); if (!error && *stat == 1) { *bno = be32_to_cpu(rec->alloc.ar_startblock); *len = be32_to_cpu(rec->alloc.ar_blockcount); } return error; } /* * Compute aligned version of the found extent. * Takes alignment and min length into account. */ STATIC void xfs_alloc_compute_aligned( xfs_alloc_arg_t *args, /* allocation argument structure */ xfs_agblock_t foundbno, /* starting block in found extent */ xfs_extlen_t foundlen, /* length in found extent */ xfs_agblock_t *resbno, /* result block number */ xfs_extlen_t *reslen) /* result length */ { xfs_agblock_t bno; xfs_extlen_t len; xfs_extlen_t diff; /* Trim busy sections out of found extent */ xfs_extent_busy_trim(args, foundbno, foundlen, &bno, &len); /* * If we have a largish extent that happens to start before min_agbno, * see if we can shift it into range... */ if (bno < args->min_agbno && bno + len > args->min_agbno) { diff = args->min_agbno - bno; if (len > diff) { bno += diff; len -= diff; } } if (args->alignment > 1 && len >= args->minlen) { xfs_agblock_t aligned_bno = roundup(bno, args->alignment); diff = aligned_bno - bno; *resbno = aligned_bno; *reslen = diff >= len ? 0 : len - diff; } else { *resbno = bno; *reslen = len; } } /* * Compute best start block and diff for "near" allocations. * freelen >= wantlen already checked by caller. */ STATIC xfs_extlen_t /* difference value (absolute) */ xfs_alloc_compute_diff( xfs_agblock_t wantbno, /* target starting block */ xfs_extlen_t wantlen, /* target length */ xfs_extlen_t alignment, /* target alignment */ char userdata, /* are we allocating data? */ xfs_agblock_t freebno, /* freespace's starting block */ xfs_extlen_t freelen, /* freespace's length */ xfs_agblock_t *newbnop) /* result: best start block from free */ { xfs_agblock_t freeend; /* end of freespace extent */ xfs_agblock_t newbno1; /* return block number */ xfs_agblock_t newbno2; /* other new block number */ xfs_extlen_t newlen1=0; /* length with newbno1 */ xfs_extlen_t newlen2=0; /* length with newbno2 */ xfs_agblock_t wantend; /* end of target extent */ ASSERT(freelen >= wantlen); freeend = freebno + freelen; wantend = wantbno + wantlen; /* * We want to allocate from the start of a free extent if it is past * the desired block or if we are allocating user data and the free * extent is before desired block. The second case is there to allow * for contiguous allocation from the remaining free space if the file * grows in the short term. */ if (freebno >= wantbno || (userdata && freeend < wantend)) { if ((newbno1 = roundup(freebno, alignment)) >= freeend) newbno1 = NULLAGBLOCK; } else if (freeend >= wantend && alignment > 1) { newbno1 = roundup(wantbno, alignment); newbno2 = newbno1 - alignment; if (newbno1 >= freeend) newbno1 = NULLAGBLOCK; else newlen1 = XFS_EXTLEN_MIN(wantlen, freeend - newbno1); if (newbno2 < freebno) newbno2 = NULLAGBLOCK; else newlen2 = XFS_EXTLEN_MIN(wantlen, freeend - newbno2); if (newbno1 != NULLAGBLOCK && newbno2 != NULLAGBLOCK) { if (newlen1 < newlen2 || (newlen1 == newlen2 && XFS_ABSDIFF(newbno1, wantbno) > XFS_ABSDIFF(newbno2, wantbno))) newbno1 = newbno2; } else if (newbno2 != NULLAGBLOCK) newbno1 = newbno2; } else if (freeend >= wantend) { newbno1 = wantbno; } else if (alignment > 1) { newbno1 = roundup(freeend - wantlen, alignment); if (newbno1 > freeend - wantlen && newbno1 - alignment >= freebno) newbno1 -= alignment; else if (newbno1 >= freeend) newbno1 = NULLAGBLOCK; } else newbno1 = freeend - wantlen; *newbnop = newbno1; return newbno1 == NULLAGBLOCK ? 0 : XFS_ABSDIFF(newbno1, wantbno); } /* * Fix up the length, based on mod and prod. * len should be k * prod + mod for some k. * If len is too small it is returned unchanged. * If len hits maxlen it is left alone. */ STATIC void xfs_alloc_fix_len( xfs_alloc_arg_t *args) /* allocation argument structure */ { xfs_extlen_t k; xfs_extlen_t rlen; ASSERT(args->mod < args->prod); rlen = args->len; ASSERT(rlen >= args->minlen); ASSERT(rlen <= args->maxlen); if (args->prod <= 1 || rlen < args->mod || rlen == args->maxlen || (args->mod == 0 && rlen < args->prod)) return; k = rlen % args->prod; if (k == args->mod) return; if (k > args->mod) rlen = rlen - (k - args->mod); else rlen = rlen - args->prod + (args->mod - k); /* casts to (int) catch length underflows */ if ((int)rlen < (int)args->minlen) return; ASSERT(rlen >= args->minlen && rlen <= args->maxlen); ASSERT(rlen % args->prod == args->mod); args->len = rlen; } /* * Fix up length if there is too little space left in the a.g. * Return 1 if ok, 0 if too little, should give up. */ STATIC int xfs_alloc_fix_minleft( xfs_alloc_arg_t *args) /* allocation argument structure */ { xfs_agf_t *agf; /* a.g. freelist header */ int diff; /* free space difference */ if (args->minleft == 0) return 1; agf = XFS_BUF_TO_AGF(args->agbp); diff = be32_to_cpu(agf->agf_freeblks) - args->len - args->minleft; if (diff >= 0) return 1; args->len += diff; /* shrink the allocated space */ /* casts to (int) catch length underflows */ if ((int)args->len >= (int)args->minlen) return 1; args->agbno = NULLAGBLOCK; return 0; } /* * Update the two btrees, logically removing from freespace the extent * starting at rbno, rlen blocks. The extent is contained within the * actual (current) free extent fbno for flen blocks. * Flags are passed in indicating whether the cursors are set to the * relevant records. */ STATIC int /* error code */ xfs_alloc_fixup_trees( xfs_btree_cur_t *cnt_cur, /* cursor for by-size btree */ xfs_btree_cur_t *bno_cur, /* cursor for by-block btree */ xfs_agblock_t fbno, /* starting block of free extent */ xfs_extlen_t flen, /* length of free extent */ xfs_agblock_t rbno, /* starting block of returned extent */ xfs_extlen_t rlen, /* length of returned extent */ int flags) /* flags, XFSA_FIXUP_... */ { int error; /* error code */ int i; /* operation results */ xfs_agblock_t nfbno1; /* first new free startblock */ xfs_agblock_t nfbno2; /* second new free startblock */ xfs_extlen_t nflen1=0; /* first new free length */ xfs_extlen_t nflen2=0; /* second new free length */ struct xfs_mount *mp; mp = cnt_cur->bc_mp; /* * Look up the record in the by-size tree if necessary. */ if (flags & XFSA_FIXUP_CNT_OK) { #ifdef DEBUG if ((error = xfs_alloc_get_rec(cnt_cur, &nfbno1, &nflen1, &i))) return error; XFS_WANT_CORRUPTED_RETURN(mp, i == 1 && nfbno1 == fbno && nflen1 == flen); #endif } else { if ((error = xfs_alloc_lookup_eq(cnt_cur, fbno, flen, &i))) return error; XFS_WANT_CORRUPTED_RETURN(mp, i == 1); } /* * Look up the record in the by-block tree if necessary. */ if (flags & XFSA_FIXUP_BNO_OK) { #ifdef DEBUG if ((error = xfs_alloc_get_rec(bno_cur, &nfbno1, &nflen1, &i))) return error; XFS_WANT_CORRUPTED_RETURN(mp, i == 1 && nfbno1 == fbno && nflen1 == flen); #endif } else { if ((error = xfs_alloc_lookup_eq(bno_cur, fbno, flen, &i))) return error; XFS_WANT_CORRUPTED_RETURN(mp, i == 1); } #ifdef DEBUG if (bno_cur->bc_nlevels == 1 && cnt_cur->bc_nlevels == 1) { struct xfs_btree_block *bnoblock; struct xfs_btree_block *cntblock; bnoblock = XFS_BUF_TO_BLOCK(bno_cur->bc_bufs[0]); cntblock = XFS_BUF_TO_BLOCK(cnt_cur->bc_bufs[0]); XFS_WANT_CORRUPTED_RETURN(mp, bnoblock->bb_numrecs == cntblock->bb_numrecs); } #endif /* * Deal with all four cases: the allocated record is contained * within the freespace record, so we can have new freespace * at either (or both) end, or no freespace remaining. */ if (rbno == fbno && rlen == flen) nfbno1 = nfbno2 = NULLAGBLOCK; else if (rbno == fbno) { nfbno1 = rbno + rlen; nflen1 = flen - rlen; nfbno2 = NULLAGBLOCK; } else if (rbno + rlen == fbno + flen) { nfbno1 = fbno; nflen1 = flen - rlen; nfbno2 = NULLAGBLOCK; } else { nfbno1 = fbno; nflen1 = rbno - fbno; nfbno2 = rbno + rlen; nflen2 = (fbno + flen) - nfbno2; } /* * Delete the entry from the by-size btree. */ if ((error = xfs_btree_delete(cnt_cur, &i))) return error; XFS_WANT_CORRUPTED_RETURN(mp, i == 1); /* * Add new by-size btree entry(s). */ if (nfbno1 != NULLAGBLOCK) { if ((error = xfs_alloc_lookup_eq(cnt_cur, nfbno1, nflen1, &i))) return error; XFS_WANT_CORRUPTED_RETURN(mp, i == 0); if ((error = xfs_btree_insert(cnt_cur, &i))) return error; XFS_WANT_CORRUPTED_RETURN(mp, i == 1); } if (nfbno2 != NULLAGBLOCK) { if ((error = xfs_alloc_lookup_eq(cnt_cur, nfbno2, nflen2, &i))) return error; XFS_WANT_CORRUPTED_RETURN(mp, i == 0); if ((error = xfs_btree_insert(cnt_cur, &i))) return error; XFS_WANT_CORRUPTED_RETURN(mp, i == 1); } /* * Fix up the by-block btree entry(s). */ if (nfbno1 == NULLAGBLOCK) { /* * No remaining freespace, just delete the by-block tree entry. */ if ((error = xfs_btree_delete(bno_cur, &i))) return error; XFS_WANT_CORRUPTED_RETURN(mp, i == 1); } else { /* * Update the by-block entry to start later|be shorter. */ if ((error = xfs_alloc_update(bno_cur, nfbno1, nflen1))) return error; } if (nfbno2 != NULLAGBLOCK) { /* * 2 resulting free entries, need to add one. */ if ((error = xfs_alloc_lookup_eq(bno_cur, nfbno2, nflen2, &i))) return error; XFS_WANT_CORRUPTED_RETURN(mp, i == 0); if ((error = xfs_btree_insert(bno_cur, &i))) return error; XFS_WANT_CORRUPTED_RETURN(mp, i == 1); } return 0; } static bool xfs_agfl_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_target->bt_mount; struct xfs_agfl *agfl = XFS_BUF_TO_AGFL(bp); int i; if (!uuid_equal(&agfl->agfl_uuid, &mp->m_sb.sb_meta_uuid)) return false; if (be32_to_cpu(agfl->agfl_magicnum) != XFS_AGFL_MAGIC) return false; /* * during growfs operations, the perag is not fully initialised, * so we can't use it for any useful checking. growfs ensures we can't * use it by using uncached buffers that don't have the perag attached * so we can detect and avoid this problem. */ if (bp->b_pag && be32_to_cpu(agfl->agfl_seqno) != bp->b_pag->pag_agno) return false; for (i = 0; i < XFS_AGFL_SIZE(mp); i++) { if (be32_to_cpu(agfl->agfl_bno[i]) != NULLAGBLOCK && be32_to_cpu(agfl->agfl_bno[i]) >= mp->m_sb.sb_agblocks) return false; } return true; } static void xfs_agfl_read_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_target->bt_mount; /* * There is no verification of non-crc AGFLs because mkfs does not * initialise the AGFL to zero or NULL. Hence the only valid part of the * AGFL is what the AGF says is active. We can't get to the AGF, so we * can't verify just those entries are valid. */ if (!xfs_sb_version_hascrc(&mp->m_sb)) return; if (!xfs_buf_verify_cksum(bp, XFS_AGFL_CRC_OFF)) xfs_buf_ioerror(bp, -EFSBADCRC); else if (!xfs_agfl_verify(bp)) xfs_buf_ioerror(bp, -EFSCORRUPTED); if (bp->b_error) xfs_verifier_error(bp); } static void xfs_agfl_write_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_target->bt_mount; struct xfs_buf_log_item *bip = bp->b_fspriv; /* no verification of non-crc AGFLs */ if (!xfs_sb_version_hascrc(&mp->m_sb)) return; if (!xfs_agfl_verify(bp)) { xfs_buf_ioerror(bp, -EFSCORRUPTED); xfs_verifier_error(bp); return; } if (bip) XFS_BUF_TO_AGFL(bp)->agfl_lsn = cpu_to_be64(bip->bli_item.li_lsn); xfs_buf_update_cksum(bp, XFS_AGFL_CRC_OFF); } const struct xfs_buf_ops xfs_agfl_buf_ops = { .verify_read = xfs_agfl_read_verify, .verify_write = xfs_agfl_write_verify, }; /* * Read in the allocation group free block array. */ STATIC int /* error */ xfs_alloc_read_agfl( xfs_mount_t *mp, /* mount point structure */ xfs_trans_t *tp, /* transaction pointer */ xfs_agnumber_t agno, /* allocation group number */ xfs_buf_t **bpp) /* buffer for the ag free block array */ { xfs_buf_t *bp; /* return value */ int error; ASSERT(agno != NULLAGNUMBER); error = xfs_trans_read_buf( mp, tp, mp->m_ddev_targp, XFS_AG_DADDR(mp, agno, XFS_AGFL_DADDR(mp)), XFS_FSS_TO_BB(mp, 1), 0, &bp, &xfs_agfl_buf_ops); if (error) return error; xfs_buf_set_ref(bp, XFS_AGFL_REF); *bpp = bp; return 0; } STATIC int xfs_alloc_update_counters( struct xfs_trans *tp, struct xfs_perag *pag, struct xfs_buf *agbp, long len) { struct xfs_agf *agf = XFS_BUF_TO_AGF(agbp); pag->pagf_freeblks += len; be32_add_cpu(&agf->agf_freeblks, len); xfs_trans_agblocks_delta(tp, len); if (unlikely(be32_to_cpu(agf->agf_freeblks) > be32_to_cpu(agf->agf_length))) return -EFSCORRUPTED; xfs_alloc_log_agf(tp, agbp, XFS_AGF_FREEBLKS); return 0; } /* * Allocation group level functions. */ /* * Allocate a variable extent in the allocation group agno. * Type and bno are used to determine where in the allocation group the * extent will start. * Extent's length (returned in *len) will be between minlen and maxlen, * and of the form k * prod + mod unless there's nothing that large. * Return the starting a.g. block, or NULLAGBLOCK if we can't do it. */ STATIC int /* error */ xfs_alloc_ag_vextent( xfs_alloc_arg_t *args) /* argument structure for allocation */ { int error=0; ASSERT(args->minlen > 0); ASSERT(args->maxlen > 0); ASSERT(args->minlen <= args->maxlen); ASSERT(args->mod < args->prod); ASSERT(args->alignment > 0); /* * Branch to correct routine based on the type. */ args->wasfromfl = 0; switch (args->type) { case XFS_ALLOCTYPE_THIS_AG: error = xfs_alloc_ag_vextent_size(args); break; case XFS_ALLOCTYPE_NEAR_BNO: error = xfs_alloc_ag_vextent_near(args); break; case XFS_ALLOCTYPE_THIS_BNO: error = xfs_alloc_ag_vextent_exact(args); break; default: ASSERT(0); /* NOTREACHED */ } if (error || args->agbno == NULLAGBLOCK) return error; ASSERT(args->len >= args->minlen); ASSERT(args->len <= args->maxlen); ASSERT(!args->wasfromfl || !args->isfl); ASSERT(args->agbno % args->alignment == 0); if (!args->wasfromfl) { error = xfs_alloc_update_counters(args->tp, args->pag, args->agbp, -((long)(args->len))); if (error) return error; ASSERT(!xfs_extent_busy_search(args->mp, args->agno, args->agbno, args->len)); } if (!args->isfl) { xfs_trans_mod_sb(args->tp, args->wasdel ? XFS_TRANS_SB_RES_FDBLOCKS : XFS_TRANS_SB_FDBLOCKS, -((long)(args->len))); } XFS_STATS_INC(xs_allocx); XFS_STATS_ADD(xs_allocb, args->len); return error; } /* * Allocate a variable extent at exactly agno/bno. * Extent's length (returned in *len) will be between minlen and maxlen, * and of the form k * prod + mod unless there's nothing that large. * Return the starting a.g. block (bno), or NULLAGBLOCK if we can't do it. */ STATIC int /* error */ xfs_alloc_ag_vextent_exact( xfs_alloc_arg_t *args) /* allocation argument structure */ { xfs_btree_cur_t *bno_cur;/* by block-number btree cursor */ xfs_btree_cur_t *cnt_cur;/* by count btree cursor */ int error; xfs_agblock_t fbno; /* start block of found extent */ xfs_extlen_t flen; /* length of found extent */ xfs_agblock_t tbno; /* start block of trimmed extent */ xfs_extlen_t tlen; /* length of trimmed extent */ xfs_agblock_t tend; /* end block of trimmed extent */ int i; /* success/failure of operation */ ASSERT(args->alignment == 1); /* * Allocate/initialize a cursor for the by-number freespace btree. */ bno_cur = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp, args->agno, XFS_BTNUM_BNO); /* * Lookup bno and minlen in the btree (minlen is irrelevant, really). * Look for the closest free block <= bno, it must contain bno * if any free block does. */ error = xfs_alloc_lookup_le(bno_cur, args->agbno, args->minlen, &i); if (error) goto error0; if (!i) goto not_found; /* * Grab the freespace record. */ error = xfs_alloc_get_rec(bno_cur, &fbno, &flen, &i); if (error) goto error0; XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0); ASSERT(fbno <= args->agbno); /* * Check for overlapping busy extents. */ xfs_extent_busy_trim(args, fbno, flen, &tbno, &tlen); /* * Give up if the start of the extent is busy, or the freespace isn't * long enough for the minimum request. */ if (tbno > args->agbno) goto not_found; if (tlen < args->minlen) goto not_found; tend = tbno + tlen; if (tend < args->agbno + args->minlen) goto not_found; /* * End of extent will be smaller of the freespace end and the * maximal requested end. * * Fix the length according to mod and prod if given. */ args->len = XFS_AGBLOCK_MIN(tend, args->agbno + args->maxlen) - args->agbno; xfs_alloc_fix_len(args); if (!xfs_alloc_fix_minleft(args)) goto not_found; ASSERT(args->agbno + args->len <= tend); /* * We are allocating agbno for args->len * Allocate/initialize a cursor for the by-size btree. */ cnt_cur = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp, args->agno, XFS_BTNUM_CNT); ASSERT(args->agbno + args->len <= be32_to_cpu(XFS_BUF_TO_AGF(args->agbp)->agf_length)); error = xfs_alloc_fixup_trees(cnt_cur, bno_cur, fbno, flen, args->agbno, args->len, XFSA_FIXUP_BNO_OK); if (error) { xfs_btree_del_cursor(cnt_cur, XFS_BTREE_ERROR); goto error0; } xfs_btree_del_cursor(bno_cur, XFS_BTREE_NOERROR); xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); args->wasfromfl = 0; trace_xfs_alloc_exact_done(args); return 0; not_found: /* Didn't find it, return null. */ xfs_btree_del_cursor(bno_cur, XFS_BTREE_NOERROR); args->agbno = NULLAGBLOCK; trace_xfs_alloc_exact_notfound(args); return 0; error0: xfs_btree_del_cursor(bno_cur, XFS_BTREE_ERROR); trace_xfs_alloc_exact_error(args); return error; } /* * Search the btree in a given direction via the search cursor and compare * the records found against the good extent we've already found. */ STATIC int xfs_alloc_find_best_extent( struct xfs_alloc_arg *args, /* allocation argument structure */ struct xfs_btree_cur **gcur, /* good cursor */ struct xfs_btree_cur **scur, /* searching cursor */ xfs_agblock_t gdiff, /* difference for search comparison */ xfs_agblock_t *sbno, /* extent found by search */ xfs_extlen_t *slen, /* extent length */ xfs_agblock_t *sbnoa, /* aligned extent found by search */ xfs_extlen_t *slena, /* aligned extent length */ int dir) /* 0 = search right, 1 = search left */ { xfs_agblock_t new; xfs_agblock_t sdiff; int error; int i; /* The good extent is perfect, no need to search. */ if (!gdiff) goto out_use_good; /* * Look until we find a better one, run out of space or run off the end. */ do { error = xfs_alloc_get_rec(*scur, sbno, slen, &i); if (error) goto error0; XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0); xfs_alloc_compute_aligned(args, *sbno, *slen, sbnoa, slena); /* * The good extent is closer than this one. */ if (!dir) { if (*sbnoa > args->max_agbno) goto out_use_good; if (*sbnoa >= args->agbno + gdiff) goto out_use_good; } else { if (*sbnoa < args->min_agbno) goto out_use_good; if (*sbnoa <= args->agbno - gdiff) goto out_use_good; } /* * Same distance, compare length and pick the best. */ if (*slena >= args->minlen) { args->len = XFS_EXTLEN_MIN(*slena, args->maxlen); xfs_alloc_fix_len(args); sdiff = xfs_alloc_compute_diff(args->agbno, args->len, args->alignment, args->userdata, *sbnoa, *slena, &new); /* * Choose closer size and invalidate other cursor. */ if (sdiff < gdiff) goto out_use_search; goto out_use_good; } if (!dir) error = xfs_btree_increment(*scur, 0, &i); else error = xfs_btree_decrement(*scur, 0, &i); if (error) goto error0; } while (i); out_use_good: xfs_btree_del_cursor(*scur, XFS_BTREE_NOERROR); *scur = NULL; return 0; out_use_search: xfs_btree_del_cursor(*gcur, XFS_BTREE_NOERROR); *gcur = NULL; return 0; error0: /* caller invalidates cursors */ return error; } /* * Allocate a variable extent near bno in the allocation group agno. * Extent's length (returned in len) will be between minlen and maxlen, * and of the form k * prod + mod unless there's nothing that large. * Return the starting a.g. block, or NULLAGBLOCK if we can't do it. */ STATIC int /* error */ xfs_alloc_ag_vextent_near( xfs_alloc_arg_t *args) /* allocation argument structure */ { xfs_btree_cur_t *bno_cur_gt; /* cursor for bno btree, right side */ xfs_btree_cur_t *bno_cur_lt; /* cursor for bno btree, left side */ xfs_btree_cur_t *cnt_cur; /* cursor for count btree */ xfs_agblock_t gtbno; /* start bno of right side entry */ xfs_agblock_t gtbnoa; /* aligned ... */ xfs_extlen_t gtdiff; /* difference to right side entry */ xfs_extlen_t gtlen; /* length of right side entry */ xfs_extlen_t gtlena; /* aligned ... */ xfs_agblock_t gtnew; /* useful start bno of right side */ int error; /* error code */ int i; /* result code, temporary */ int j; /* result code, temporary */ xfs_agblock_t ltbno; /* start bno of left side entry */ xfs_agblock_t ltbnoa; /* aligned ... */ xfs_extlen_t ltdiff; /* difference to left side entry */ xfs_extlen_t ltlen; /* length of left side entry */ xfs_extlen_t ltlena; /* aligned ... */ xfs_agblock_t ltnew; /* useful start bno of left side */ xfs_extlen_t rlen; /* length of returned extent */ int forced = 0; #ifdef DEBUG /* * Randomly don't execute the first algorithm. */ int dofirst; /* set to do first algorithm */ dofirst = prandom_u32() & 1; #endif /* handle unitialized agbno range so caller doesn't have to */ if (!args->min_agbno && !args->max_agbno) args->max_agbno = args->mp->m_sb.sb_agblocks - 1; ASSERT(args->min_agbno <= args->max_agbno); /* clamp agbno to the range if it's outside */ if (args->agbno < args->min_agbno) args->agbno = args->min_agbno; if (args->agbno > args->max_agbno) args->agbno = args->max_agbno; restart: bno_cur_lt = NULL; bno_cur_gt = NULL; ltlen = 0; gtlena = 0; ltlena = 0; /* * Get a cursor for the by-size btree. */ cnt_cur = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp, args->agno, XFS_BTNUM_CNT); /* * See if there are any free extents as big as maxlen. */ if ((error = xfs_alloc_lookup_ge(cnt_cur, 0, args->maxlen, &i))) goto error0; /* * If none, then pick up the last entry in the tree unless the * tree is empty. */ if (!i) { if ((error = xfs_alloc_ag_vextent_small(args, cnt_cur, <bno, <len, &i))) goto error0; if (i == 0 || ltlen == 0) { xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); trace_xfs_alloc_near_noentry(args); return 0; } ASSERT(i == 1); } args->wasfromfl = 0; /* * First algorithm. * If the requested extent is large wrt the freespaces available * in this a.g., then the cursor will be pointing to a btree entry * near the right edge of the tree. If it's in the last btree leaf * block, then we just examine all the entries in that block * that are big enough, and pick the best one. * This is written as a while loop so we can break out of it, * but we never loop back to the top. */ while (xfs_btree_islastblock(cnt_cur, 0)) { xfs_extlen_t bdiff; int besti=0; xfs_extlen_t blen=0; xfs_agblock_t bnew=0; #ifdef DEBUG if (dofirst) break; #endif /* * Start from the entry that lookup found, sequence through * all larger free blocks. If we're actually pointing at a * record smaller than maxlen, go to the start of this block, * and skip all those smaller than minlen. */ if (ltlen || args->alignment > 1) { cnt_cur->bc_ptrs[0] = 1; do { if ((error = xfs_alloc_get_rec(cnt_cur, <bno, <len, &i))) goto error0; XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0); if (ltlen >= args->minlen) break; if ((error = xfs_btree_increment(cnt_cur, 0, &i))) goto error0; } while (i); ASSERT(ltlen >= args->minlen); if (!i) break; } i = cnt_cur->bc_ptrs[0]; for (j = 1, blen = 0, bdiff = 0; !error && j && (blen < args->maxlen || bdiff > 0); error = xfs_btree_increment(cnt_cur, 0, &j)) { /* * For each entry, decide if it's better than * the previous best entry. */ if ((error = xfs_alloc_get_rec(cnt_cur, <bno, <len, &i))) goto error0; XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0); xfs_alloc_compute_aligned(args, ltbno, ltlen, <bnoa, <lena); if (ltlena < args->minlen) continue; if (ltbnoa < args->min_agbno || ltbnoa > args->max_agbno) continue; args->len = XFS_EXTLEN_MIN(ltlena, args->maxlen); xfs_alloc_fix_len(args); ASSERT(args->len >= args->minlen); if (args->len < blen) continue; ltdiff = xfs_alloc_compute_diff(args->agbno, args->len, args->alignment, args->userdata, ltbnoa, ltlena, <new); if (ltnew != NULLAGBLOCK && (args->len > blen || ltdiff < bdiff)) { bdiff = ltdiff; bnew = ltnew; blen = args->len; besti = cnt_cur->bc_ptrs[0]; } } /* * It didn't work. We COULD be in a case where * there's a good record somewhere, so try again. */ if (blen == 0) break; /* * Point at the best entry, and retrieve it again. */ cnt_cur->bc_ptrs[0] = besti; if ((error = xfs_alloc_get_rec(cnt_cur, <bno, <len, &i))) goto error0; XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0); ASSERT(ltbno + ltlen <= be32_to_cpu(XFS_BUF_TO_AGF(args->agbp)->agf_length)); args->len = blen; if (!xfs_alloc_fix_minleft(args)) { xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); trace_xfs_alloc_near_nominleft(args); return 0; } blen = args->len; /* * We are allocating starting at bnew for blen blocks. */ args->agbno = bnew; ASSERT(bnew >= ltbno); ASSERT(bnew + blen <= ltbno + ltlen); /* * Set up a cursor for the by-bno tree. */ bno_cur_lt = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp, args->agno, XFS_BTNUM_BNO); /* * Fix up the btree entries. */ if ((error = xfs_alloc_fixup_trees(cnt_cur, bno_cur_lt, ltbno, ltlen, bnew, blen, XFSA_FIXUP_CNT_OK))) goto error0; xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); xfs_btree_del_cursor(bno_cur_lt, XFS_BTREE_NOERROR); trace_xfs_alloc_near_first(args); return 0; } /* * Second algorithm. * Search in the by-bno tree to the left and to the right * simultaneously, until in each case we find a space big enough, * or run into the edge of the tree. When we run into the edge, * we deallocate that cursor. * If both searches succeed, we compare the two spaces and pick * the better one. * With alignment, it's possible for both to fail; the upper * level algorithm that picks allocation groups for allocations * is not supposed to do this. */ /* * Allocate and initialize the cursor for the leftward search. */ bno_cur_lt = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp, args->agno, XFS_BTNUM_BNO); /* * Lookup <= bno to find the leftward search's starting point. */ if ((error = xfs_alloc_lookup_le(bno_cur_lt, args->agbno, args->maxlen, &i))) goto error0; if (!i) { /* * Didn't find anything; use this cursor for the rightward * search. */ bno_cur_gt = bno_cur_lt; bno_cur_lt = NULL; } /* * Found something. Duplicate the cursor for the rightward search. */ else if ((error = xfs_btree_dup_cursor(bno_cur_lt, &bno_cur_gt))) goto error0; /* * Increment the cursor, so we will point at the entry just right * of the leftward entry if any, or to the leftmost entry. */ if ((error = xfs_btree_increment(bno_cur_gt, 0, &i))) goto error0; if (!i) { /* * It failed, there are no rightward entries. */ xfs_btree_del_cursor(bno_cur_gt, XFS_BTREE_NOERROR); bno_cur_gt = NULL; } /* * Loop going left with the leftward cursor, right with the * rightward cursor, until either both directions give up or * we find an entry at least as big as minlen. */ do { if (bno_cur_lt) { if ((error = xfs_alloc_get_rec(bno_cur_lt, <bno, <len, &i))) goto error0; XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0); xfs_alloc_compute_aligned(args, ltbno, ltlen, <bnoa, <lena); if (ltlena >= args->minlen && ltbnoa >= args->min_agbno) break; if ((error = xfs_btree_decrement(bno_cur_lt, 0, &i))) goto error0; if (!i || ltbnoa < args->min_agbno) { xfs_btree_del_cursor(bno_cur_lt, XFS_BTREE_NOERROR); bno_cur_lt = NULL; } } if (bno_cur_gt) { if ((error = xfs_alloc_get_rec(bno_cur_gt, >bno, >len, &i))) goto error0; XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0); xfs_alloc_compute_aligned(args, gtbno, gtlen, >bnoa, >lena); if (gtlena >= args->minlen && gtbnoa <= args->max_agbno) break; if ((error = xfs_btree_increment(bno_cur_gt, 0, &i))) goto error0; if (!i || gtbnoa > args->max_agbno) { xfs_btree_del_cursor(bno_cur_gt, XFS_BTREE_NOERROR); bno_cur_gt = NULL; } } } while (bno_cur_lt || bno_cur_gt); /* * Got both cursors still active, need to find better entry. */ if (bno_cur_lt && bno_cur_gt) { if (ltlena >= args->minlen) { /* * Left side is good, look for a right side entry. */ args->len = XFS_EXTLEN_MIN(ltlena, args->maxlen); xfs_alloc_fix_len(args); ltdiff = xfs_alloc_compute_diff(args->agbno, args->len, args->alignment, args->userdata, ltbnoa, ltlena, <new); error = xfs_alloc_find_best_extent(args, &bno_cur_lt, &bno_cur_gt, ltdiff, >bno, >len, >bnoa, >lena, 0 /* search right */); } else { ASSERT(gtlena >= args->minlen); /* * Right side is good, look for a left side entry. */ args->len = XFS_EXTLEN_MIN(gtlena, args->maxlen); xfs_alloc_fix_len(args); gtdiff = xfs_alloc_compute_diff(args->agbno, args->len, args->alignment, args->userdata, gtbnoa, gtlena, >new); error = xfs_alloc_find_best_extent(args, &bno_cur_gt, &bno_cur_lt, gtdiff, <bno, <len, <bnoa, <lena, 1 /* search left */); } if (error) goto error0; } /* * If we couldn't get anything, give up. */ if (bno_cur_lt == NULL && bno_cur_gt == NULL) { xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); if (!forced++) { trace_xfs_alloc_near_busy(args); xfs_log_force(args->mp, XFS_LOG_SYNC); goto restart; } trace_xfs_alloc_size_neither(args); args->agbno = NULLAGBLOCK; return 0; } /* * At this point we have selected a freespace entry, either to the * left or to the right. If it's on the right, copy all the * useful variables to the "left" set so we only have one * copy of this code. */ if (bno_cur_gt) { bno_cur_lt = bno_cur_gt; bno_cur_gt = NULL; ltbno = gtbno; ltbnoa = gtbnoa; ltlen = gtlen; ltlena = gtlena; j = 1; } else j = 0; /* * Fix up the length and compute the useful address. */ args->len = XFS_EXTLEN_MIN(ltlena, args->maxlen); xfs_alloc_fix_len(args); if (!xfs_alloc_fix_minleft(args)) { trace_xfs_alloc_near_nominleft(args); xfs_btree_del_cursor(bno_cur_lt, XFS_BTREE_NOERROR); xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); return 0; } rlen = args->len; (void)xfs_alloc_compute_diff(args->agbno, rlen, args->alignment, args->userdata, ltbnoa, ltlena, <new); ASSERT(ltnew >= ltbno); ASSERT(ltnew + rlen <= ltbnoa + ltlena); ASSERT(ltnew + rlen <= be32_to_cpu(XFS_BUF_TO_AGF(args->agbp)->agf_length)); ASSERT(ltnew >= args->min_agbno && ltnew <= args->max_agbno); args->agbno = ltnew; if ((error = xfs_alloc_fixup_trees(cnt_cur, bno_cur_lt, ltbno, ltlen, ltnew, rlen, XFSA_FIXUP_BNO_OK))) goto error0; if (j) trace_xfs_alloc_near_greater(args); else trace_xfs_alloc_near_lesser(args); xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); xfs_btree_del_cursor(bno_cur_lt, XFS_BTREE_NOERROR); return 0; error0: trace_xfs_alloc_near_error(args); if (cnt_cur != NULL) xfs_btree_del_cursor(cnt_cur, XFS_BTREE_ERROR); if (bno_cur_lt != NULL) xfs_btree_del_cursor(bno_cur_lt, XFS_BTREE_ERROR); if (bno_cur_gt != NULL) xfs_btree_del_cursor(bno_cur_gt, XFS_BTREE_ERROR); return error; } /* * Allocate a variable extent anywhere in the allocation group agno. * Extent's length (returned in len) will be between minlen and maxlen, * and of the form k * prod + mod unless there's nothing that large. * Return the starting a.g. block, or NULLAGBLOCK if we can't do it. */ STATIC int /* error */ xfs_alloc_ag_vextent_size( xfs_alloc_arg_t *args) /* allocation argument structure */ { xfs_btree_cur_t *bno_cur; /* cursor for bno btree */ xfs_btree_cur_t *cnt_cur; /* cursor for cnt btree */ int error; /* error result */ xfs_agblock_t fbno; /* start of found freespace */ xfs_extlen_t flen; /* length of found freespace */ int i; /* temp status variable */ xfs_agblock_t rbno; /* returned block number */ xfs_extlen_t rlen; /* length of returned extent */ int forced = 0; restart: /* * Allocate and initialize a cursor for the by-size btree. */ cnt_cur = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp, args->agno, XFS_BTNUM_CNT); bno_cur = NULL; /* * Look for an entry >= maxlen+alignment-1 blocks. */ if ((error = xfs_alloc_lookup_ge(cnt_cur, 0, args->maxlen + args->alignment - 1, &i))) goto error0; /* * If none or we have busy extents that we cannot allocate from, then * we have to settle for a smaller extent. In the case that there are * no large extents, this will return the last entry in the tree unless * the tree is empty. In the case that there are only busy large * extents, this will return the largest small extent unless there * are no smaller extents available. */ if (!i || forced > 1) { error = xfs_alloc_ag_vextent_small(args, cnt_cur, &fbno, &flen, &i); if (error) goto error0; if (i == 0 || flen == 0) { xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); trace_xfs_alloc_size_noentry(args); return 0; } ASSERT(i == 1); xfs_alloc_compute_aligned(args, fbno, flen, &rbno, &rlen); } else { /* * Search for a non-busy extent that is large enough. * If we are at low space, don't check, or if we fall of * the end of the btree, turn off the busy check and * restart. */ for (;;) { error = xfs_alloc_get_rec(cnt_cur, &fbno, &flen, &i); if (error) goto error0; XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0); xfs_alloc_compute_aligned(args, fbno, flen, &rbno, &rlen); if (rlen >= args->maxlen) break; error = xfs_btree_increment(cnt_cur, 0, &i); if (error) goto error0; if (i == 0) { /* * Our only valid extents must have been busy. * Make it unbusy by forcing the log out and * retrying. If we've been here before, forcing * the log isn't making the extents available, * which means they have probably been freed in * this transaction. In that case, we have to * give up on them and we'll attempt a minlen * allocation the next time around. */ xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); trace_xfs_alloc_size_busy(args); if (!forced++) xfs_log_force(args->mp, XFS_LOG_SYNC); goto restart; } } } /* * In the first case above, we got the last entry in the * by-size btree. Now we check to see if the space hits maxlen * once aligned; if not, we search left for something better. * This can't happen in the second case above. */ rlen = XFS_EXTLEN_MIN(args->maxlen, rlen); XFS_WANT_CORRUPTED_GOTO(args->mp, rlen == 0 || (rlen <= flen && rbno + rlen <= fbno + flen), error0); if (rlen < args->maxlen) { xfs_agblock_t bestfbno; xfs_extlen_t bestflen; xfs_agblock_t bestrbno; xfs_extlen_t bestrlen; bestrlen = rlen; bestrbno = rbno; bestflen = flen; bestfbno = fbno; for (;;) { if ((error = xfs_btree_decrement(cnt_cur, 0, &i))) goto error0; if (i == 0) break; if ((error = xfs_alloc_get_rec(cnt_cur, &fbno, &flen, &i))) goto error0; XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0); if (flen < bestrlen) break; xfs_alloc_compute_aligned(args, fbno, flen, &rbno, &rlen); rlen = XFS_EXTLEN_MIN(args->maxlen, rlen); XFS_WANT_CORRUPTED_GOTO(args->mp, rlen == 0 || (rlen <= flen && rbno + rlen <= fbno + flen), error0); if (rlen > bestrlen) { bestrlen = rlen; bestrbno = rbno; bestflen = flen; bestfbno = fbno; if (rlen == args->maxlen) break; } } if ((error = xfs_alloc_lookup_eq(cnt_cur, bestfbno, bestflen, &i))) goto error0; XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0); rlen = bestrlen; rbno = bestrbno; flen = bestflen; fbno = bestfbno; } args->wasfromfl = 0; /* * Fix up the length. */ args->len = rlen; if (rlen < args->minlen) { if (!forced++) { xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); trace_xfs_alloc_size_busy(args); xfs_log_force(args->mp, XFS_LOG_SYNC); goto restart; } goto out_nominleft; } xfs_alloc_fix_len(args); if (!xfs_alloc_fix_minleft(args)) goto out_nominleft; rlen = args->len; XFS_WANT_CORRUPTED_GOTO(args->mp, rlen <= flen, error0); /* * Allocate and initialize a cursor for the by-block tree. */ bno_cur = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp, args->agno, XFS_BTNUM_BNO); if ((error = xfs_alloc_fixup_trees(cnt_cur, bno_cur, fbno, flen, rbno, rlen, XFSA_FIXUP_CNT_OK))) goto error0; xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); xfs_btree_del_cursor(bno_cur, XFS_BTREE_NOERROR); cnt_cur = bno_cur = NULL; args->len = rlen; args->agbno = rbno; XFS_WANT_CORRUPTED_GOTO(args->mp, args->agbno + args->len <= be32_to_cpu(XFS_BUF_TO_AGF(args->agbp)->agf_length), error0); trace_xfs_alloc_size_done(args); return 0; error0: trace_xfs_alloc_size_error(args); if (cnt_cur) xfs_btree_del_cursor(cnt_cur, XFS_BTREE_ERROR); if (bno_cur) xfs_btree_del_cursor(bno_cur, XFS_BTREE_ERROR); return error; out_nominleft: xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); trace_xfs_alloc_size_nominleft(args); args->agbno = NULLAGBLOCK; return 0; } /* * Deal with the case where only small freespaces remain. * Either return the contents of the last freespace record, * or allocate space from the freelist if there is nothing in the tree. */ STATIC int /* error */ xfs_alloc_ag_vextent_small( xfs_alloc_arg_t *args, /* allocation argument structure */ xfs_btree_cur_t *ccur, /* by-size cursor */ xfs_agblock_t *fbnop, /* result block number */ xfs_extlen_t *flenp, /* result length */ int *stat) /* status: 0-freelist, 1-normal/none */ { int error; xfs_agblock_t fbno; xfs_extlen_t flen; int i; if ((error = xfs_btree_decrement(ccur, 0, &i))) goto error0; if (i) { if ((error = xfs_alloc_get_rec(ccur, &fbno, &flen, &i))) goto error0; XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0); } /* * Nothing in the btree, try the freelist. Make sure * to respect minleft even when pulling from the * freelist. */ else if (args->minlen == 1 && args->alignment == 1 && !args->isfl && (be32_to_cpu(XFS_BUF_TO_AGF(args->agbp)->agf_flcount) > args->minleft)) { error = xfs_alloc_get_freelist(args->tp, args->agbp, &fbno, 0); if (error) goto error0; if (fbno != NULLAGBLOCK) { xfs_extent_busy_reuse(args->mp, args->agno, fbno, 1, args->userdata); if (args->userdata) { xfs_buf_t *bp; bp = xfs_btree_get_bufs(args->mp, args->tp, args->agno, fbno, 0); xfs_trans_binval(args->tp, bp); } args->len = 1; args->agbno = fbno; XFS_WANT_CORRUPTED_GOTO(args->mp, args->agbno + args->len <= be32_to_cpu(XFS_BUF_TO_AGF(args->agbp)->agf_length), error0); args->wasfromfl = 1; trace_xfs_alloc_small_freelist(args); *stat = 0; return 0; } /* * Nothing in the freelist. */ else flen = 0; } /* * Can't allocate from the freelist for some reason. */ else { fbno = NULLAGBLOCK; flen = 0; } /* * Can't do the allocation, give up. */ if (flen < args->minlen) { args->agbno = NULLAGBLOCK; trace_xfs_alloc_small_notenough(args); flen = 0; } *fbnop = fbno; *flenp = flen; *stat = 1; trace_xfs_alloc_small_done(args); return 0; error0: trace_xfs_alloc_small_error(args); return error; } /* * Free the extent starting at agno/bno for length. */ STATIC int /* error */ xfs_free_ag_extent( xfs_trans_t *tp, /* transaction pointer */ xfs_buf_t *agbp, /* buffer for a.g. freelist header */ xfs_agnumber_t agno, /* allocation group number */ xfs_agblock_t bno, /* starting block number */ xfs_extlen_t len, /* length of extent */ int isfl) /* set if is freelist blocks - no sb acctg */ { xfs_btree_cur_t *bno_cur; /* cursor for by-block btree */ xfs_btree_cur_t *cnt_cur; /* cursor for by-size btree */ int error; /* error return value */ xfs_agblock_t gtbno; /* start of right neighbor block */ xfs_extlen_t gtlen; /* length of right neighbor block */ int haveleft; /* have a left neighbor block */ int haveright; /* have a right neighbor block */ int i; /* temp, result code */ xfs_agblock_t ltbno; /* start of left neighbor block */ xfs_extlen_t ltlen; /* length of left neighbor block */ xfs_mount_t *mp; /* mount point struct for filesystem */ xfs_agblock_t nbno; /* new starting block of freespace */ xfs_extlen_t nlen; /* new length of freespace */ xfs_perag_t *pag; /* per allocation group data */ mp = tp->t_mountp; /* * Allocate and initialize a cursor for the by-block btree. */ bno_cur = xfs_allocbt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_BNO); cnt_cur = NULL; /* * Look for a neighboring block on the left (lower block numbers) * that is contiguous with this space. */ if ((error = xfs_alloc_lookup_le(bno_cur, bno, len, &haveleft))) goto error0; if (haveleft) { /* * There is a block to our left. */ if ((error = xfs_alloc_get_rec(bno_cur, <bno, <len, &i))) goto error0; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0); /* * It's not contiguous, though. */ if (ltbno + ltlen < bno) haveleft = 0; else { /* * If this failure happens the request to free this * space was invalid, it's (partly) already free. * Very bad. */ XFS_WANT_CORRUPTED_GOTO(mp, ltbno + ltlen <= bno, error0); } } /* * Look for a neighboring block on the right (higher block numbers) * that is contiguous with this space. */ if ((error = xfs_btree_increment(bno_cur, 0, &haveright))) goto error0; if (haveright) { /* * There is a block to our right. */ if ((error = xfs_alloc_get_rec(bno_cur, >bno, >len, &i))) goto error0; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0); /* * It's not contiguous, though. */ if (bno + len < gtbno) haveright = 0; else { /* * If this failure happens the request to free this * space was invalid, it's (partly) already free. * Very bad. */ XFS_WANT_CORRUPTED_GOTO(mp, gtbno >= bno + len, error0); } } /* * Now allocate and initialize a cursor for the by-size tree. */ cnt_cur = xfs_allocbt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_CNT); /* * Have both left and right contiguous neighbors. * Merge all three into a single free block. */ if (haveleft && haveright) { /* * Delete the old by-size entry on the left. */ if ((error = xfs_alloc_lookup_eq(cnt_cur, ltbno, ltlen, &i))) goto error0; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0); if ((error = xfs_btree_delete(cnt_cur, &i))) goto error0; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0); /* * Delete the old by-size entry on the right. */ if ((error = xfs_alloc_lookup_eq(cnt_cur, gtbno, gtlen, &i))) goto error0; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0); if ((error = xfs_btree_delete(cnt_cur, &i))) goto error0; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0); /* * Delete the old by-block entry for the right block. */ if ((error = xfs_btree_delete(bno_cur, &i))) goto error0; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0); /* * Move the by-block cursor back to the left neighbor. */ if ((error = xfs_btree_decrement(bno_cur, 0, &i))) goto error0; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0); #ifdef DEBUG /* * Check that this is the right record: delete didn't * mangle the cursor. */ { xfs_agblock_t xxbno; xfs_extlen_t xxlen; if ((error = xfs_alloc_get_rec(bno_cur, &xxbno, &xxlen, &i))) goto error0; XFS_WANT_CORRUPTED_GOTO(mp, i == 1 && xxbno == ltbno && xxlen == ltlen, error0); } #endif /* * Update remaining by-block entry to the new, joined block. */ nbno = ltbno; nlen = len + ltlen + gtlen; if ((error = xfs_alloc_update(bno_cur, nbno, nlen))) goto error0; } /* * Have only a left contiguous neighbor. * Merge it together with the new freespace. */ else if (haveleft) { /* * Delete the old by-size entry on the left. */ if ((error = xfs_alloc_lookup_eq(cnt_cur, ltbno, ltlen, &i))) goto error0; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0); if ((error = xfs_btree_delete(cnt_cur, &i))) goto error0; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0); /* * Back up the by-block cursor to the left neighbor, and * update its length. */ if ((error = xfs_btree_decrement(bno_cur, 0, &i))) goto error0; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0); nbno = ltbno; nlen = len + ltlen; if ((error = xfs_alloc_update(bno_cur, nbno, nlen))) goto error0; } /* * Have only a right contiguous neighbor. * Merge it together with the new freespace. */ else if (haveright) { /* * Delete the old by-size entry on the right. */ if ((error = xfs_alloc_lookup_eq(cnt_cur, gtbno, gtlen, &i))) goto error0; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0); if ((error = xfs_btree_delete(cnt_cur, &i))) goto error0; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0); /* * Update the starting block and length of the right * neighbor in the by-block tree. */ nbno = bno; nlen = len + gtlen; if ((error = xfs_alloc_update(bno_cur, nbno, nlen))) goto error0; } /* * No contiguous neighbors. * Insert the new freespace into the by-block tree. */ else { nbno = bno; nlen = len; if ((error = xfs_btree_insert(bno_cur, &i))) goto error0; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0); } xfs_btree_del_cursor(bno_cur, XFS_BTREE_NOERROR); bno_cur = NULL; /* * In all cases we need to insert the new freespace in the by-size tree. */ if ((error = xfs_alloc_lookup_eq(cnt_cur, nbno, nlen, &i))) goto error0; XFS_WANT_CORRUPTED_GOTO(mp, i == 0, error0); if ((error = xfs_btree_insert(cnt_cur, &i))) goto error0; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0); xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); cnt_cur = NULL; /* * Update the freespace totals in the ag and superblock. */ pag = xfs_perag_get(mp, agno); error = xfs_alloc_update_counters(tp, pag, agbp, len); xfs_perag_put(pag); if (error) goto error0; if (!isfl) xfs_trans_mod_sb(tp, XFS_TRANS_SB_FDBLOCKS, (long)len); XFS_STATS_INC(xs_freex); XFS_STATS_ADD(xs_freeb, len); trace_xfs_free_extent(mp, agno, bno, len, isfl, haveleft, haveright); return 0; error0: trace_xfs_free_extent(mp, agno, bno, len, isfl, -1, -1); if (bno_cur) xfs_btree_del_cursor(bno_cur, XFS_BTREE_ERROR); if (cnt_cur) xfs_btree_del_cursor(cnt_cur, XFS_BTREE_ERROR); return error; } /* * Visible (exported) allocation/free functions. * Some of these are used just by xfs_alloc_btree.c and this file. */ /* * Compute and fill in value of m_ag_maxlevels. */ void xfs_alloc_compute_maxlevels( xfs_mount_t *mp) /* file system mount structure */ { int level; uint maxblocks; uint maxleafents; int minleafrecs; int minnoderecs; maxleafents = (mp->m_sb.sb_agblocks + 1) / 2; minleafrecs = mp->m_alloc_mnr[0]; minnoderecs = mp->m_alloc_mnr[1]; maxblocks = (maxleafents + minleafrecs - 1) / minleafrecs; for (level = 1; maxblocks > 1; level++) maxblocks = (maxblocks + minnoderecs - 1) / minnoderecs; mp->m_ag_maxlevels = level; } /* * Find the length of the longest extent in an AG. */ xfs_extlen_t xfs_alloc_longest_free_extent( struct xfs_mount *mp, struct xfs_perag *pag, xfs_extlen_t need) { xfs_extlen_t delta = 0; if (need > pag->pagf_flcount) delta = need - pag->pagf_flcount; if (pag->pagf_longest > delta) return pag->pagf_longest - delta; return pag->pagf_flcount > 0 || pag->pagf_longest > 0; } unsigned int xfs_alloc_min_freelist( struct xfs_mount *mp, struct xfs_perag *pag) { unsigned int min_free; /* space needed by-bno freespace btree */ min_free = min_t(unsigned int, pag->pagf_levels[XFS_BTNUM_BNOi] + 1, mp->m_ag_maxlevels); /* space needed by-size freespace btree */ min_free += min_t(unsigned int, pag->pagf_levels[XFS_BTNUM_CNTi] + 1, mp->m_ag_maxlevels); return min_free; } /* * Check if the operation we are fixing up the freelist for should go ahead or * not. If we are freeing blocks, we always allow it, otherwise the allocation * is dependent on whether the size and shape of free space available will * permit the requested allocation to take place. */ static bool xfs_alloc_space_available( struct xfs_alloc_arg *args, xfs_extlen_t min_free, int flags) { struct xfs_perag *pag = args->pag; xfs_extlen_t longest; int available; if (flags & XFS_ALLOC_FLAG_FREEING) return true; /* do we have enough contiguous free space for the allocation? */ longest = xfs_alloc_longest_free_extent(args->mp, pag, min_free); if ((args->minlen + args->alignment + args->minalignslop - 1) > longest) return false; /* do have enough free space remaining for the allocation? */ available = (int)(pag->pagf_freeblks + pag->pagf_flcount - min_free - args->total); if (available < (int)args->minleft) return false; return true; } /* * Decide whether to use this allocation group for this allocation. * If so, fix up the btree freelist's size. */ int /* error */ xfs_alloc_fix_freelist( struct xfs_alloc_arg *args, /* allocation argument structure */ int flags) /* XFS_ALLOC_FLAG_... */ { struct xfs_mount *mp = args->mp; struct xfs_perag *pag = args->pag; struct xfs_trans *tp = args->tp; struct xfs_buf *agbp = NULL; struct xfs_buf *agflbp = NULL; struct xfs_alloc_arg targs; /* local allocation arguments */ xfs_agblock_t bno; /* freelist block */ xfs_extlen_t need; /* total blocks needed in freelist */ int error = 0; if (!pag->pagf_init) { error = xfs_alloc_read_agf(mp, tp, args->agno, flags, &agbp); if (error) goto out_no_agbp; if (!pag->pagf_init) { ASSERT(flags & XFS_ALLOC_FLAG_TRYLOCK); ASSERT(!(flags & XFS_ALLOC_FLAG_FREEING)); goto out_agbp_relse; } } /* * If this is a metadata preferred pag and we are user data then try * somewhere else if we are not being asked to try harder at this * point */ if (pag->pagf_metadata && args->userdata && (flags & XFS_ALLOC_FLAG_TRYLOCK)) { ASSERT(!(flags & XFS_ALLOC_FLAG_FREEING)); goto out_agbp_relse; } need = xfs_alloc_min_freelist(mp, pag); if (!xfs_alloc_space_available(args, need, flags)) goto out_agbp_relse; /* * Get the a.g. freespace buffer. * Can fail if we're not blocking on locks, and it's held. */ if (!agbp) { error = xfs_alloc_read_agf(mp, tp, args->agno, flags, &agbp); if (error) goto out_no_agbp; if (!agbp) { ASSERT(flags & XFS_ALLOC_FLAG_TRYLOCK); ASSERT(!(flags & XFS_ALLOC_FLAG_FREEING)); goto out_no_agbp; } } /* If there isn't enough total space or single-extent, reject it. */ need = xfs_alloc_min_freelist(mp, pag); if (!xfs_alloc_space_available(args, need, flags)) goto out_agbp_relse; /* * Make the freelist shorter if it's too long. * * Note that from this point onwards, we will always release the agf and * agfl buffers on error. This handles the case where we error out and * the buffers are clean or may not have been joined to the transaction * and hence need to be released manually. If they have been joined to * the transaction, then xfs_trans_brelse() will handle them * appropriately based on the recursion count and dirty state of the * buffer. * * XXX (dgc): When we have lots of free space, does this buy us * anything other than extra overhead when we need to put more blocks * back on the free list? Maybe we should only do this when space is * getting low or the AGFL is more than half full? */ while (pag->pagf_flcount > need) { struct xfs_buf *bp; error = xfs_alloc_get_freelist(tp, agbp, &bno, 0); if (error) goto out_agbp_relse; error = xfs_free_ag_extent(tp, agbp, args->agno, bno, 1, 1); if (error) goto out_agbp_relse; bp = xfs_btree_get_bufs(mp, tp, args->agno, bno, 0); xfs_trans_binval(tp, bp); } memset(&targs, 0, sizeof(targs)); targs.tp = tp; targs.mp = mp; targs.agbp = agbp; targs.agno = args->agno; targs.alignment = targs.minlen = targs.prod = targs.isfl = 1; targs.type = XFS_ALLOCTYPE_THIS_AG; targs.pag = pag; error = xfs_alloc_read_agfl(mp, tp, targs.agno, &agflbp); if (error) goto out_agbp_relse; /* Make the freelist longer if it's too short. */ while (pag->pagf_flcount < need) { targs.agbno = 0; targs.maxlen = need - pag->pagf_flcount; /* Allocate as many blocks as possible at once. */ error = xfs_alloc_ag_vextent(&targs); if (error) goto out_agflbp_relse; /* * Stop if we run out. Won't happen if callers are obeying * the restrictions correctly. Can happen for free calls * on a completely full ag. */ if (targs.agbno == NULLAGBLOCK) { if (flags & XFS_ALLOC_FLAG_FREEING) break; goto out_agflbp_relse; } /* * Put each allocated block on the list. */ for (bno = targs.agbno; bno < targs.agbno + targs.len; bno++) { error = xfs_alloc_put_freelist(tp, agbp, agflbp, bno, 0); if (error) goto out_agflbp_relse; } } xfs_trans_brelse(tp, agflbp); args->agbp = agbp; return 0; out_agflbp_relse: xfs_trans_brelse(tp, agflbp); out_agbp_relse: if (agbp) xfs_trans_brelse(tp, agbp); out_no_agbp: args->agbp = NULL; return error; } /* * Get a block from the freelist. * Returns with the buffer for the block gotten. */ int /* error */ xfs_alloc_get_freelist( xfs_trans_t *tp, /* transaction pointer */ xfs_buf_t *agbp, /* buffer containing the agf structure */ xfs_agblock_t *bnop, /* block address retrieved from freelist */ int btreeblk) /* destination is a AGF btree */ { xfs_agf_t *agf; /* a.g. freespace structure */ xfs_buf_t *agflbp;/* buffer for a.g. freelist structure */ xfs_agblock_t bno; /* block number returned */ __be32 *agfl_bno; int error; int logflags; xfs_mount_t *mp = tp->t_mountp; xfs_perag_t *pag; /* per allocation group data */ /* * Freelist is empty, give up. */ agf = XFS_BUF_TO_AGF(agbp); if (!agf->agf_flcount) { *bnop = NULLAGBLOCK; return 0; } /* * Read the array of free blocks. */ error = xfs_alloc_read_agfl(mp, tp, be32_to_cpu(agf->agf_seqno), &agflbp); if (error) return error; /* * Get the block number and update the data structures. */ agfl_bno = XFS_BUF_TO_AGFL_BNO(mp, agflbp); bno = be32_to_cpu(agfl_bno[be32_to_cpu(agf->agf_flfirst)]); be32_add_cpu(&agf->agf_flfirst, 1); xfs_trans_brelse(tp, agflbp); if (be32_to_cpu(agf->agf_flfirst) == XFS_AGFL_SIZE(mp)) agf->agf_flfirst = 0; pag = xfs_perag_get(mp, be32_to_cpu(agf->agf_seqno)); be32_add_cpu(&agf->agf_flcount, -1); xfs_trans_agflist_delta(tp, -1); pag->pagf_flcount--; xfs_perag_put(pag); logflags = XFS_AGF_FLFIRST | XFS_AGF_FLCOUNT; if (btreeblk) { be32_add_cpu(&agf->agf_btreeblks, 1); pag->pagf_btreeblks++; logflags |= XFS_AGF_BTREEBLKS; } xfs_alloc_log_agf(tp, agbp, logflags); *bnop = bno; return 0; } /* * Log the given fields from the agf structure. */ void xfs_alloc_log_agf( xfs_trans_t *tp, /* transaction pointer */ xfs_buf_t *bp, /* buffer for a.g. freelist header */ int fields) /* mask of fields to be logged (XFS_AGF_...) */ { int first; /* first byte offset */ int last; /* last byte offset */ static const short offsets[] = { offsetof(xfs_agf_t, agf_magicnum), offsetof(xfs_agf_t, agf_versionnum), offsetof(xfs_agf_t, agf_seqno), offsetof(xfs_agf_t, agf_length), offsetof(xfs_agf_t, agf_roots[0]), offsetof(xfs_agf_t, agf_levels[0]), offsetof(xfs_agf_t, agf_flfirst), offsetof(xfs_agf_t, agf_fllast), offsetof(xfs_agf_t, agf_flcount), offsetof(xfs_agf_t, agf_freeblks), offsetof(xfs_agf_t, agf_longest), offsetof(xfs_agf_t, agf_btreeblks), offsetof(xfs_agf_t, agf_uuid), sizeof(xfs_agf_t) }; trace_xfs_agf(tp->t_mountp, XFS_BUF_TO_AGF(bp), fields, _RET_IP_); xfs_trans_buf_set_type(tp, bp, XFS_BLFT_AGF_BUF); xfs_btree_offsets(fields, offsets, XFS_AGF_NUM_BITS, &first, &last); xfs_trans_log_buf(tp, bp, (uint)first, (uint)last); } /* * Interface for inode allocation to force the pag data to be initialized. */ int /* error */ xfs_alloc_pagf_init( xfs_mount_t *mp, /* file system mount structure */ xfs_trans_t *tp, /* transaction pointer */ xfs_agnumber_t agno, /* allocation group number */ int flags) /* XFS_ALLOC_FLAGS_... */ { xfs_buf_t *bp; int error; if ((error = xfs_alloc_read_agf(mp, tp, agno, flags, &bp))) return error; if (bp) xfs_trans_brelse(tp, bp); return 0; } /* * Put the block on the freelist for the allocation group. */ int /* error */ xfs_alloc_put_freelist( xfs_trans_t *tp, /* transaction pointer */ xfs_buf_t *agbp, /* buffer for a.g. freelist header */ xfs_buf_t *agflbp,/* buffer for a.g. free block array */ xfs_agblock_t bno, /* block being freed */ int btreeblk) /* block came from a AGF btree */ { xfs_agf_t *agf; /* a.g. freespace structure */ __be32 *blockp;/* pointer to array entry */ int error; int logflags; xfs_mount_t *mp; /* mount structure */ xfs_perag_t *pag; /* per allocation group data */ __be32 *agfl_bno; int startoff; agf = XFS_BUF_TO_AGF(agbp); mp = tp->t_mountp; if (!agflbp && (error = xfs_alloc_read_agfl(mp, tp, be32_to_cpu(agf->agf_seqno), &agflbp))) return error; be32_add_cpu(&agf->agf_fllast, 1); if (be32_to_cpu(agf->agf_fllast) == XFS_AGFL_SIZE(mp)) agf->agf_fllast = 0; pag = xfs_perag_get(mp, be32_to_cpu(agf->agf_seqno)); be32_add_cpu(&agf->agf_flcount, 1); xfs_trans_agflist_delta(tp, 1); pag->pagf_flcount++; logflags = XFS_AGF_FLLAST | XFS_AGF_FLCOUNT; if (btreeblk) { be32_add_cpu(&agf->agf_btreeblks, -1); pag->pagf_btreeblks--; logflags |= XFS_AGF_BTREEBLKS; } xfs_perag_put(pag); xfs_alloc_log_agf(tp, agbp, logflags); ASSERT(be32_to_cpu(agf->agf_flcount) <= XFS_AGFL_SIZE(mp)); agfl_bno = XFS_BUF_TO_AGFL_BNO(mp, agflbp); blockp = &agfl_bno[be32_to_cpu(agf->agf_fllast)]; *blockp = cpu_to_be32(bno); startoff = (char *)blockp - (char *)agflbp->b_addr; xfs_alloc_log_agf(tp, agbp, logflags); xfs_trans_buf_set_type(tp, agflbp, XFS_BLFT_AGFL_BUF); xfs_trans_log_buf(tp, agflbp, startoff, startoff + sizeof(xfs_agblock_t) - 1); return 0; } static bool xfs_agf_verify( struct xfs_mount *mp, struct xfs_buf *bp) { struct xfs_agf *agf = XFS_BUF_TO_AGF(bp); if (xfs_sb_version_hascrc(&mp->m_sb) && !uuid_equal(&agf->agf_uuid, &mp->m_sb.sb_meta_uuid)) return false; if (!(agf->agf_magicnum == cpu_to_be32(XFS_AGF_MAGIC) && XFS_AGF_GOOD_VERSION(be32_to_cpu(agf->agf_versionnum)) && be32_to_cpu(agf->agf_freeblks) <= be32_to_cpu(agf->agf_length) && be32_to_cpu(agf->agf_flfirst) < XFS_AGFL_SIZE(mp) && be32_to_cpu(agf->agf_fllast) < XFS_AGFL_SIZE(mp) && be32_to_cpu(agf->agf_flcount) <= XFS_AGFL_SIZE(mp))) return false; if (be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNO]) > XFS_BTREE_MAXLEVELS || be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]) > XFS_BTREE_MAXLEVELS) return false; /* * during growfs operations, the perag is not fully initialised, * so we can't use it for any useful checking. growfs ensures we can't * use it by using uncached buffers that don't have the perag attached * so we can detect and avoid this problem. */ if (bp->b_pag && be32_to_cpu(agf->agf_seqno) != bp->b_pag->pag_agno) return false; if (xfs_sb_version_haslazysbcount(&mp->m_sb) && be32_to_cpu(agf->agf_btreeblks) > be32_to_cpu(agf->agf_length)) return false; return true;; } static void xfs_agf_read_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_target->bt_mount; if (xfs_sb_version_hascrc(&mp->m_sb) && !xfs_buf_verify_cksum(bp, XFS_AGF_CRC_OFF)) xfs_buf_ioerror(bp, -EFSBADCRC); else if (XFS_TEST_ERROR(!xfs_agf_verify(mp, bp), mp, XFS_ERRTAG_ALLOC_READ_AGF, XFS_RANDOM_ALLOC_READ_AGF)) xfs_buf_ioerror(bp, -EFSCORRUPTED); if (bp->b_error) xfs_verifier_error(bp); } static void xfs_agf_write_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_target->bt_mount; struct xfs_buf_log_item *bip = bp->b_fspriv; if (!xfs_agf_verify(mp, bp)) { xfs_buf_ioerror(bp, -EFSCORRUPTED); xfs_verifier_error(bp); return; } if (!xfs_sb_version_hascrc(&mp->m_sb)) return; if (bip) XFS_BUF_TO_AGF(bp)->agf_lsn = cpu_to_be64(bip->bli_item.li_lsn); xfs_buf_update_cksum(bp, XFS_AGF_CRC_OFF); } const struct xfs_buf_ops xfs_agf_buf_ops = { .verify_read = xfs_agf_read_verify, .verify_write = xfs_agf_write_verify, }; /* * Read in the allocation group header (free/alloc section). */ int /* error */ xfs_read_agf( struct xfs_mount *mp, /* mount point structure */ struct xfs_trans *tp, /* transaction pointer */ xfs_agnumber_t agno, /* allocation group number */ int flags, /* XFS_BUF_ */ struct xfs_buf **bpp) /* buffer for the ag freelist header */ { int error; trace_xfs_read_agf(mp, agno); ASSERT(agno != NULLAGNUMBER); error = xfs_trans_read_buf( mp, tp, mp->m_ddev_targp, XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR(mp)), XFS_FSS_TO_BB(mp, 1), flags, bpp, &xfs_agf_buf_ops); if (error) return error; if (!*bpp) return 0; ASSERT(!(*bpp)->b_error); xfs_buf_set_ref(*bpp, XFS_AGF_REF); return 0; } /* * Read in the allocation group header (free/alloc section). */ int /* error */ xfs_alloc_read_agf( struct xfs_mount *mp, /* mount point structure */ struct xfs_trans *tp, /* transaction pointer */ xfs_agnumber_t agno, /* allocation group number */ int flags, /* XFS_ALLOC_FLAG_... */ struct xfs_buf **bpp) /* buffer for the ag freelist header */ { struct xfs_agf *agf; /* ag freelist header */ struct xfs_perag *pag; /* per allocation group data */ int error; trace_xfs_alloc_read_agf(mp, agno); ASSERT(agno != NULLAGNUMBER); error = xfs_read_agf(mp, tp, agno, (flags & XFS_ALLOC_FLAG_TRYLOCK) ? XBF_TRYLOCK : 0, bpp); if (error) return error; if (!*bpp) return 0; ASSERT(!(*bpp)->b_error); agf = XFS_BUF_TO_AGF(*bpp); pag = xfs_perag_get(mp, agno); if (!pag->pagf_init) { pag->pagf_freeblks = be32_to_cpu(agf->agf_freeblks); pag->pagf_btreeblks = be32_to_cpu(agf->agf_btreeblks); pag->pagf_flcount = be32_to_cpu(agf->agf_flcount); pag->pagf_longest = be32_to_cpu(agf->agf_longest); pag->pagf_levels[XFS_BTNUM_BNOi] = be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNOi]); pag->pagf_levels[XFS_BTNUM_CNTi] = be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNTi]); spin_lock_init(&pag->pagb_lock); pag->pagb_count = 0; /* XXX: pagb_tree doesn't exist in userspace */ //pag->pagb_tree = RB_ROOT; pag->pagf_init = 1; } #ifdef DEBUG else if (!XFS_FORCED_SHUTDOWN(mp)) { ASSERT(pag->pagf_freeblks == be32_to_cpu(agf->agf_freeblks)); ASSERT(pag->pagf_btreeblks == be32_to_cpu(agf->agf_btreeblks)); ASSERT(pag->pagf_flcount == be32_to_cpu(agf->agf_flcount)); ASSERT(pag->pagf_longest == be32_to_cpu(agf->agf_longest)); ASSERT(pag->pagf_levels[XFS_BTNUM_BNOi] == be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNOi])); ASSERT(pag->pagf_levels[XFS_BTNUM_CNTi] == be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNTi])); } #endif xfs_perag_put(pag); return 0; } /* * Allocate an extent (variable-size). * Depending on the allocation type, we either look in a single allocation * group or loop over the allocation groups to find the result. */ int /* error */ xfs_alloc_vextent( xfs_alloc_arg_t *args) /* allocation argument structure */ { xfs_agblock_t agsize; /* allocation group size */ int error; int flags; /* XFS_ALLOC_FLAG_... locking flags */ xfs_extlen_t minleft;/* minimum left value, temp copy */ xfs_mount_t *mp; /* mount structure pointer */ xfs_agnumber_t sagno; /* starting allocation group number */ xfs_alloctype_t type; /* input allocation type */ int bump_rotor = 0; int no_min = 0; xfs_agnumber_t rotorstep = xfs_rotorstep; /* inode32 agf stepper */ mp = args->mp; type = args->otype = args->type; args->agbno = NULLAGBLOCK; /* * Just fix this up, for the case where the last a.g. is shorter * (or there's only one a.g.) and the caller couldn't easily figure * that out (xfs_bmap_alloc). */ agsize = mp->m_sb.sb_agblocks; if (args->maxlen > agsize) args->maxlen = agsize; if (args->alignment == 0) args->alignment = 1; ASSERT(XFS_FSB_TO_AGNO(mp, args->fsbno) < mp->m_sb.sb_agcount); ASSERT(XFS_FSB_TO_AGBNO(mp, args->fsbno) < agsize); ASSERT(args->minlen <= args->maxlen); ASSERT(args->minlen <= agsize); ASSERT(args->mod < args->prod); if (XFS_FSB_TO_AGNO(mp, args->fsbno) >= mp->m_sb.sb_agcount || XFS_FSB_TO_AGBNO(mp, args->fsbno) >= agsize || args->minlen > args->maxlen || args->minlen > agsize || args->mod >= args->prod) { args->fsbno = NULLFSBLOCK; trace_xfs_alloc_vextent_badargs(args); return 0; } minleft = args->minleft; switch (type) { case XFS_ALLOCTYPE_THIS_AG: case XFS_ALLOCTYPE_NEAR_BNO: case XFS_ALLOCTYPE_THIS_BNO: /* * These three force us into a single a.g. */ args->agno = XFS_FSB_TO_AGNO(mp, args->fsbno); args->pag = xfs_perag_get(mp, args->agno); args->minleft = 0; error = xfs_alloc_fix_freelist(args, 0); args->minleft = minleft; if (error) { trace_xfs_alloc_vextent_nofix(args); goto error0; } if (!args->agbp) { trace_xfs_alloc_vextent_noagbp(args); break; } args->agbno = XFS_FSB_TO_AGBNO(mp, args->fsbno); if ((error = xfs_alloc_ag_vextent(args))) goto error0; break; case XFS_ALLOCTYPE_START_BNO: /* * Try near allocation first, then anywhere-in-ag after * the first a.g. fails. */ if ((args->userdata == XFS_ALLOC_INITIAL_USER_DATA) && (mp->m_flags & XFS_MOUNT_32BITINODES)) { args->fsbno = XFS_AGB_TO_FSB(mp, ((mp->m_agfrotor / rotorstep) % mp->m_sb.sb_agcount), 0); bump_rotor = 1; } args->agbno = XFS_FSB_TO_AGBNO(mp, args->fsbno); args->type = XFS_ALLOCTYPE_NEAR_BNO; /* FALLTHROUGH */ case XFS_ALLOCTYPE_ANY_AG: case XFS_ALLOCTYPE_START_AG: case XFS_ALLOCTYPE_FIRST_AG: /* * Rotate through the allocation groups looking for a winner. */ if (type == XFS_ALLOCTYPE_ANY_AG) { /* * Start with the last place we left off. */ args->agno = sagno = (mp->m_agfrotor / rotorstep) % mp->m_sb.sb_agcount; args->type = XFS_ALLOCTYPE_THIS_AG; flags = XFS_ALLOC_FLAG_TRYLOCK; } else if (type == XFS_ALLOCTYPE_FIRST_AG) { /* * Start with allocation group given by bno. */ args->agno = XFS_FSB_TO_AGNO(mp, args->fsbno); args->type = XFS_ALLOCTYPE_THIS_AG; sagno = 0; flags = 0; } else { if (type == XFS_ALLOCTYPE_START_AG) args->type = XFS_ALLOCTYPE_THIS_AG; /* * Start with the given allocation group. */ args->agno = sagno = XFS_FSB_TO_AGNO(mp, args->fsbno); flags = XFS_ALLOC_FLAG_TRYLOCK; } /* * Loop over allocation groups twice; first time with * trylock set, second time without. */ for (;;) { args->pag = xfs_perag_get(mp, args->agno); if (no_min) args->minleft = 0; error = xfs_alloc_fix_freelist(args, flags); args->minleft = minleft; if (error) { trace_xfs_alloc_vextent_nofix(args); goto error0; } /* * If we get a buffer back then the allocation will fly. */ if (args->agbp) { if ((error = xfs_alloc_ag_vextent(args))) goto error0; break; } trace_xfs_alloc_vextent_loopfailed(args); /* * Didn't work, figure out the next iteration. */ if (args->agno == sagno && type == XFS_ALLOCTYPE_START_BNO) args->type = XFS_ALLOCTYPE_THIS_AG; /* * For the first allocation, we can try any AG to get * space. However, if we already have allocated a * block, we don't want to try AGs whose number is below * sagno. Otherwise, we may end up with out-of-order * locking of AGF, which might cause deadlock. */ if (++(args->agno) == mp->m_sb.sb_agcount) { if (args->firstblock != NULLFSBLOCK) args->agno = sagno; else args->agno = 0; } /* * Reached the starting a.g., must either be done * or switch to non-trylock mode. */ if (args->agno == sagno) { if (no_min == 1) { args->agbno = NULLAGBLOCK; trace_xfs_alloc_vextent_allfailed(args); break; } if (flags == 0) { no_min = 1; } else { flags = 0; if (type == XFS_ALLOCTYPE_START_BNO) { args->agbno = XFS_FSB_TO_AGBNO(mp, args->fsbno); args->type = XFS_ALLOCTYPE_NEAR_BNO; } } } xfs_perag_put(args->pag); } if (bump_rotor || (type == XFS_ALLOCTYPE_ANY_AG)) { if (args->agno == sagno) mp->m_agfrotor = (mp->m_agfrotor + 1) % (mp->m_sb.sb_agcount * rotorstep); else mp->m_agfrotor = (args->agno * rotorstep + 1) % (mp->m_sb.sb_agcount * rotorstep); } break; default: ASSERT(0); /* NOTREACHED */ } if (args->agbno == NULLAGBLOCK) args->fsbno = NULLFSBLOCK; else { args->fsbno = XFS_AGB_TO_FSB(mp, args->agno, args->agbno); #ifdef DEBUG ASSERT(args->len >= args->minlen); ASSERT(args->len <= args->maxlen); ASSERT(args->agbno % args->alignment == 0); XFS_AG_CHECK_DADDR(mp, XFS_FSB_TO_DADDR(mp, args->fsbno), args->len); #endif } xfs_perag_put(args->pag); return 0; error0: xfs_perag_put(args->pag); return error; } /* * Free an extent. * Just break up the extent address and hand off to xfs_free_ag_extent * after fixing up the freelist. */ int /* error */ xfs_free_extent( xfs_trans_t *tp, /* transaction pointer */ xfs_fsblock_t bno, /* starting block number of extent */ xfs_extlen_t len) /* length of extent */ { xfs_alloc_arg_t args; int error; ASSERT(len != 0); memset(&args, 0, sizeof(xfs_alloc_arg_t)); args.tp = tp; args.mp = tp->t_mountp; /* * validate that the block number is legal - the enables us to detect * and handle a silent filesystem corruption rather than crashing. */ args.agno = XFS_FSB_TO_AGNO(args.mp, bno); if (args.agno >= args.mp->m_sb.sb_agcount) return -EFSCORRUPTED; args.agbno = XFS_FSB_TO_AGBNO(args.mp, bno); if (args.agbno >= args.mp->m_sb.sb_agblocks) return -EFSCORRUPTED; args.pag = xfs_perag_get(args.mp, args.agno); ASSERT(args.pag); error = xfs_alloc_fix_freelist(&args, XFS_ALLOC_FLAG_FREEING); if (error) goto error0; /* validate the extent size is legal now we have the agf locked */ if (args.agbno + len > be32_to_cpu(XFS_BUF_TO_AGF(args.agbp)->agf_length)) { error = -EFSCORRUPTED; goto error0; } error = xfs_free_ag_extent(tp, args.agbp, args.agno, args.agbno, len, 0); if (!error) xfs_extent_busy_insert(tp, args.agno, args.agbno, len, 0); error0: xfs_perag_put(args.pag); return error; } partclone-0.2.86/src/xfs/xfs_alloc.h000066400000000000000000000213271262102574200173160ustar00rootroot00000000000000/* * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __XFS_ALLOC_H__ #define __XFS_ALLOC_H__ struct xfs_buf; struct xfs_btree_cur; struct xfs_mount; struct xfs_perag; struct xfs_trans; extern struct workqueue_struct *xfs_alloc_wq; /* * Freespace allocation types. Argument to xfs_alloc_[v]extent. */ #define XFS_ALLOCTYPE_ANY_AG 0x01 /* allocate anywhere, use rotor */ #define XFS_ALLOCTYPE_FIRST_AG 0x02 /* ... start at ag 0 */ #define XFS_ALLOCTYPE_START_AG 0x04 /* anywhere, start in this a.g. */ #define XFS_ALLOCTYPE_THIS_AG 0x08 /* anywhere in this a.g. */ #define XFS_ALLOCTYPE_START_BNO 0x10 /* near this block else anywhere */ #define XFS_ALLOCTYPE_NEAR_BNO 0x20 /* in this a.g. and near this block */ #define XFS_ALLOCTYPE_THIS_BNO 0x40 /* at exactly this block */ /* this should become an enum again when the tracing code is fixed */ typedef unsigned int xfs_alloctype_t; #define XFS_ALLOC_TYPES \ { XFS_ALLOCTYPE_ANY_AG, "ANY_AG" }, \ { XFS_ALLOCTYPE_FIRST_AG, "FIRST_AG" }, \ { XFS_ALLOCTYPE_START_AG, "START_AG" }, \ { XFS_ALLOCTYPE_THIS_AG, "THIS_AG" }, \ { XFS_ALLOCTYPE_START_BNO, "START_BNO" }, \ { XFS_ALLOCTYPE_NEAR_BNO, "NEAR_BNO" }, \ { XFS_ALLOCTYPE_THIS_BNO, "THIS_BNO" } /* * Flags for xfs_alloc_fix_freelist. */ #define XFS_ALLOC_FLAG_TRYLOCK 0x00000001 /* use trylock for buffer locking */ #define XFS_ALLOC_FLAG_FREEING 0x00000002 /* indicate caller is freeing extents*/ /* * In order to avoid ENOSPC-related deadlock caused by * out-of-order locking of AGF buffer (PV 947395), we place * constraints on the relationship among actual allocations for * data blocks, freelist blocks, and potential file data bmap * btree blocks. However, these restrictions may result in no * actual space allocated for a delayed extent, for example, a data * block in a certain AG is allocated but there is no additional * block for the additional bmap btree block due to a split of the * bmap btree of the file. The result of this may lead to an * infinite loop in xfssyncd when the file gets flushed to disk and * all delayed extents need to be actually allocated. To get around * this, we explicitly set aside a few blocks which will not be * reserved in delayed allocation. Considering the minimum number of * needed freelist blocks is 4 fsbs _per AG_, a potential split of file's bmap * btree requires 1 fsb, so we set the number of set-aside blocks * to 4 + 4*agcount. */ #define XFS_ALLOC_SET_ASIDE(mp) (4 + ((mp)->m_sb.sb_agcount * 4)) /* * When deciding how much space to allocate out of an AG, we limit the * allocation maximum size to the size the AG. However, we cannot use all the * blocks in the AG - some are permanently used by metadata. These * blocks are generally: * - the AG superblock, AGF, AGI and AGFL * - the AGF (bno and cnt) and AGI btree root blocks * - 4 blocks on the AGFL according to XFS_ALLOC_SET_ASIDE() limits * * The AG headers are sector sized, so the amount of space they take up is * dependent on filesystem geometry. The others are all single blocks. */ #define XFS_ALLOC_AG_MAX_USABLE(mp) \ ((mp)->m_sb.sb_agblocks - XFS_BB_TO_FSB(mp, XFS_FSS_TO_BB(mp, 4)) - 7) /* * Argument structure for xfs_alloc routines. * This is turned into a structure to avoid having 20 arguments passed * down several levels of the stack. */ typedef struct xfs_alloc_arg { struct xfs_trans *tp; /* transaction pointer */ struct xfs_mount *mp; /* file system mount point */ struct xfs_buf *agbp; /* buffer for a.g. freelist header */ struct xfs_perag *pag; /* per-ag struct for this agno */ xfs_fsblock_t fsbno; /* file system block number */ xfs_agnumber_t agno; /* allocation group number */ xfs_agblock_t agbno; /* allocation group-relative block # */ xfs_extlen_t minlen; /* minimum size of extent */ xfs_extlen_t maxlen; /* maximum size of extent */ xfs_extlen_t mod; /* mod value for extent size */ xfs_extlen_t prod; /* prod value for extent size */ xfs_extlen_t minleft; /* min blocks must be left after us */ xfs_extlen_t total; /* total blocks needed in xaction */ xfs_extlen_t alignment; /* align answer to multiple of this */ xfs_extlen_t minalignslop; /* slop for minlen+alignment calcs */ xfs_agblock_t min_agbno; /* set an agbno range for NEAR allocs */ xfs_agblock_t max_agbno; /* ... */ xfs_extlen_t len; /* output: actual size of extent */ xfs_alloctype_t type; /* allocation type XFS_ALLOCTYPE_... */ xfs_alloctype_t otype; /* original allocation type */ char wasdel; /* set if allocation was prev delayed */ char wasfromfl; /* set if allocation is from freelist */ char isfl; /* set if is freelist blocks - !acctg */ char userdata; /* set if this is user data */ xfs_fsblock_t firstblock; /* io first block allocated */ } xfs_alloc_arg_t; /* * Defines for userdata */ #define XFS_ALLOC_USERDATA 1 /* allocation is for user data*/ #define XFS_ALLOC_INITIAL_USER_DATA 2 /* special case start of file */ xfs_extlen_t xfs_alloc_longest_free_extent(struct xfs_mount *mp, struct xfs_perag *pag, xfs_extlen_t need); unsigned int xfs_alloc_min_freelist(struct xfs_mount *mp, struct xfs_perag *pag); /* * Compute and fill in value of m_ag_maxlevels. */ void xfs_alloc_compute_maxlevels( struct xfs_mount *mp); /* file system mount structure */ /* * Get a block from the freelist. * Returns with the buffer for the block gotten. */ int /* error */ xfs_alloc_get_freelist( struct xfs_trans *tp, /* transaction pointer */ struct xfs_buf *agbp, /* buffer containing the agf structure */ xfs_agblock_t *bnop, /* block address retrieved from freelist */ int btreeblk); /* destination is a AGF btree */ /* * Log the given fields from the agf structure. */ void xfs_alloc_log_agf( struct xfs_trans *tp, /* transaction pointer */ struct xfs_buf *bp, /* buffer for a.g. freelist header */ int fields);/* mask of fields to be logged (XFS_AGF_...) */ /* * Interface for inode allocation to force the pag data to be initialized. */ int /* error */ xfs_alloc_pagf_init( struct xfs_mount *mp, /* file system mount structure */ struct xfs_trans *tp, /* transaction pointer */ xfs_agnumber_t agno, /* allocation group number */ int flags); /* XFS_ALLOC_FLAGS_... */ /* * Put the block on the freelist for the allocation group. */ int /* error */ xfs_alloc_put_freelist( struct xfs_trans *tp, /* transaction pointer */ struct xfs_buf *agbp, /* buffer for a.g. freelist header */ struct xfs_buf *agflbp,/* buffer for a.g. free block array */ xfs_agblock_t bno, /* block being freed */ int btreeblk); /* owner was a AGF btree */ /* * Read in the allocation group header (free/alloc section). */ int /* error */ xfs_alloc_read_agf( struct xfs_mount *mp, /* mount point structure */ struct xfs_trans *tp, /* transaction pointer */ xfs_agnumber_t agno, /* allocation group number */ int flags, /* XFS_ALLOC_FLAG_... */ struct xfs_buf **bpp); /* buffer for the ag freelist header */ /* * Allocate an extent (variable-size). */ int /* error */ xfs_alloc_vextent( xfs_alloc_arg_t *args); /* allocation argument structure */ /* * Free an extent. */ int /* error */ xfs_free_extent( struct xfs_trans *tp, /* transaction pointer */ xfs_fsblock_t bno, /* starting block number of extent */ xfs_extlen_t len); /* length of extent */ int /* error */ xfs_alloc_lookup_le( struct xfs_btree_cur *cur, /* btree cursor */ xfs_agblock_t bno, /* starting block of extent */ xfs_extlen_t len, /* length of extent */ int *stat); /* success/failure */ int /* error */ xfs_alloc_lookup_ge( struct xfs_btree_cur *cur, /* btree cursor */ xfs_agblock_t bno, /* starting block of extent */ xfs_extlen_t len, /* length of extent */ int *stat); /* success/failure */ int /* error */ xfs_alloc_get_rec( struct xfs_btree_cur *cur, /* btree cursor */ xfs_agblock_t *bno, /* output: starting block of extent */ xfs_extlen_t *len, /* output: length of extent */ int *stat); /* output: success/failure */ int xfs_read_agf(struct xfs_mount *mp, struct xfs_trans *tp, xfs_agnumber_t agno, int flags, struct xfs_buf **bpp); int xfs_alloc_fix_freelist(struct xfs_alloc_arg *args, int flags); #endif /* __XFS_ALLOC_H__ */ partclone-0.2.86/src/xfs/xfs_alloc_btree.c000066400000000000000000000312151262102574200204670ustar00rootroot00000000000000/* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_sb.h" #include "xfs_mount.h" #include "xfs_btree.h" #include "xfs_alloc_btree.h" #include "xfs_alloc.h" #include "xfs_trace.h" #include "xfs_cksum.h" #include "xfs_trans.h" STATIC struct xfs_btree_cur * xfs_allocbt_dup_cursor( struct xfs_btree_cur *cur) { return xfs_allocbt_init_cursor(cur->bc_mp, cur->bc_tp, cur->bc_private.a.agbp, cur->bc_private.a.agno, cur->bc_btnum); } STATIC void xfs_allocbt_set_root( struct xfs_btree_cur *cur, union xfs_btree_ptr *ptr, int inc) { struct xfs_buf *agbp = cur->bc_private.a.agbp; struct xfs_agf *agf = XFS_BUF_TO_AGF(agbp); xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno); int btnum = cur->bc_btnum; struct xfs_perag *pag = xfs_perag_get(cur->bc_mp, seqno); ASSERT(ptr->s != 0); agf->agf_roots[btnum] = ptr->s; be32_add_cpu(&agf->agf_levels[btnum], inc); pag->pagf_levels[btnum] += inc; xfs_perag_put(pag); xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_ROOTS | XFS_AGF_LEVELS); } STATIC int xfs_allocbt_alloc_block( struct xfs_btree_cur *cur, union xfs_btree_ptr *start, union xfs_btree_ptr *new, int *stat) { int error; xfs_agblock_t bno; XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY); /* Allocate the new block from the freelist. If we can't, give up. */ error = xfs_alloc_get_freelist(cur->bc_tp, cur->bc_private.a.agbp, &bno, 1); if (error) { XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR); return error; } if (bno == NULLAGBLOCK) { XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); *stat = 0; return 0; } xfs_extent_busy_reuse(cur->bc_mp, cur->bc_private.a.agno, bno, 1, false); xfs_trans_agbtree_delta(cur->bc_tp, 1); new->s = cpu_to_be32(bno); XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); *stat = 1; return 0; } STATIC int xfs_allocbt_free_block( struct xfs_btree_cur *cur, struct xfs_buf *bp) { struct xfs_buf *agbp = cur->bc_private.a.agbp; struct xfs_agf *agf = XFS_BUF_TO_AGF(agbp); xfs_agblock_t bno; int error; bno = xfs_daddr_to_agbno(cur->bc_mp, XFS_BUF_ADDR(bp)); error = xfs_alloc_put_freelist(cur->bc_tp, agbp, NULL, bno, 1); if (error) return error; xfs_extent_busy_insert(cur->bc_tp, be32_to_cpu(agf->agf_seqno), bno, 1, XFS_EXTENT_BUSY_SKIP_DISCARD); xfs_trans_agbtree_delta(cur->bc_tp, -1); xfs_trans_binval(cur->bc_tp, bp); return 0; } /* * Update the longest extent in the AGF */ STATIC void xfs_allocbt_update_lastrec( struct xfs_btree_cur *cur, struct xfs_btree_block *block, union xfs_btree_rec *rec, int ptr, int reason) { struct xfs_agf *agf = XFS_BUF_TO_AGF(cur->bc_private.a.agbp); xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno); struct xfs_perag *pag; __be32 len; int numrecs; ASSERT(cur->bc_btnum == XFS_BTNUM_CNT); switch (reason) { case LASTREC_UPDATE: /* * If this is the last leaf block and it's the last record, * then update the size of the longest extent in the AG. */ if (ptr != xfs_btree_get_numrecs(block)) return; len = rec->alloc.ar_blockcount; break; case LASTREC_INSREC: if (be32_to_cpu(rec->alloc.ar_blockcount) <= be32_to_cpu(agf->agf_longest)) return; len = rec->alloc.ar_blockcount; break; case LASTREC_DELREC: numrecs = xfs_btree_get_numrecs(block); if (ptr <= numrecs) return; ASSERT(ptr == numrecs + 1); if (numrecs) { xfs_alloc_rec_t *rrp; rrp = XFS_ALLOC_REC_ADDR(cur->bc_mp, block, numrecs); len = rrp->ar_blockcount; } else { len = 0; } break; default: ASSERT(0); return; } agf->agf_longest = len; pag = xfs_perag_get(cur->bc_mp, seqno); pag->pagf_longest = be32_to_cpu(len); xfs_perag_put(pag); xfs_alloc_log_agf(cur->bc_tp, cur->bc_private.a.agbp, XFS_AGF_LONGEST); } STATIC int xfs_allocbt_get_minrecs( struct xfs_btree_cur *cur, int level) { return cur->bc_mp->m_alloc_mnr[level != 0]; } STATIC int xfs_allocbt_get_maxrecs( struct xfs_btree_cur *cur, int level) { return cur->bc_mp->m_alloc_mxr[level != 0]; } STATIC void xfs_allocbt_init_key_from_rec( union xfs_btree_key *key, union xfs_btree_rec *rec) { ASSERT(rec->alloc.ar_startblock != 0); key->alloc.ar_startblock = rec->alloc.ar_startblock; key->alloc.ar_blockcount = rec->alloc.ar_blockcount; } STATIC void xfs_allocbt_init_rec_from_key( union xfs_btree_key *key, union xfs_btree_rec *rec) { ASSERT(key->alloc.ar_startblock != 0); rec->alloc.ar_startblock = key->alloc.ar_startblock; rec->alloc.ar_blockcount = key->alloc.ar_blockcount; } STATIC void xfs_allocbt_init_rec_from_cur( struct xfs_btree_cur *cur, union xfs_btree_rec *rec) { ASSERT(cur->bc_rec.a.ar_startblock != 0); rec->alloc.ar_startblock = cpu_to_be32(cur->bc_rec.a.ar_startblock); rec->alloc.ar_blockcount = cpu_to_be32(cur->bc_rec.a.ar_blockcount); } STATIC void xfs_allocbt_init_ptr_from_cur( struct xfs_btree_cur *cur, union xfs_btree_ptr *ptr) { struct xfs_agf *agf = XFS_BUF_TO_AGF(cur->bc_private.a.agbp); ASSERT(cur->bc_private.a.agno == be32_to_cpu(agf->agf_seqno)); ASSERT(agf->agf_roots[cur->bc_btnum] != 0); ptr->s = agf->agf_roots[cur->bc_btnum]; } STATIC __int64_t xfs_allocbt_key_diff( struct xfs_btree_cur *cur, union xfs_btree_key *key) { xfs_alloc_rec_incore_t *rec = &cur->bc_rec.a; xfs_alloc_key_t *kp = &key->alloc; __int64_t diff; if (cur->bc_btnum == XFS_BTNUM_BNO) { return (__int64_t)be32_to_cpu(kp->ar_startblock) - rec->ar_startblock; } diff = (__int64_t)be32_to_cpu(kp->ar_blockcount) - rec->ar_blockcount; if (diff) return diff; return (__int64_t)be32_to_cpu(kp->ar_startblock) - rec->ar_startblock; } static bool xfs_allocbt_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_target->bt_mount; struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); struct xfs_perag *pag = bp->b_pag; unsigned int level; /* * magic number and level verification * * During growfs operations, we can't verify the exact level or owner as * the perag is not fully initialised and hence not attached to the * buffer. In this case, check against the maximum tree depth. * * Similarly, during log recovery we will have a perag structure * attached, but the agf information will not yet have been initialised * from the on disk AGF. Again, we can only check against maximum limits * in this case. */ level = be16_to_cpu(block->bb_level); switch (block->bb_magic) { case cpu_to_be32(XFS_ABTB_CRC_MAGIC): if (!xfs_sb_version_hascrc(&mp->m_sb)) return false; if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_meta_uuid)) return false; if (block->bb_u.s.bb_blkno != cpu_to_be64(bp->b_bn)) return false; if (pag && be32_to_cpu(block->bb_u.s.bb_owner) != pag->pag_agno) return false; /* fall through */ case cpu_to_be32(XFS_ABTB_MAGIC): if (pag && pag->pagf_init) { if (level >= pag->pagf_levels[XFS_BTNUM_BNOi]) return false; } else if (level >= mp->m_ag_maxlevels) return false; break; case cpu_to_be32(XFS_ABTC_CRC_MAGIC): if (!xfs_sb_version_hascrc(&mp->m_sb)) return false; if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_meta_uuid)) return false; if (block->bb_u.s.bb_blkno != cpu_to_be64(bp->b_bn)) return false; if (pag && be32_to_cpu(block->bb_u.s.bb_owner) != pag->pag_agno) return false; /* fall through */ case cpu_to_be32(XFS_ABTC_MAGIC): if (pag && pag->pagf_init) { if (level >= pag->pagf_levels[XFS_BTNUM_CNTi]) return false; } else if (level >= mp->m_ag_maxlevels) return false; break; default: return false; } /* numrecs verification */ if (be16_to_cpu(block->bb_numrecs) > mp->m_alloc_mxr[level != 0]) return false; /* sibling pointer verification */ if (!block->bb_u.s.bb_leftsib || (be32_to_cpu(block->bb_u.s.bb_leftsib) >= mp->m_sb.sb_agblocks && block->bb_u.s.bb_leftsib != cpu_to_be32(NULLAGBLOCK))) return false; if (!block->bb_u.s.bb_rightsib || (be32_to_cpu(block->bb_u.s.bb_rightsib) >= mp->m_sb.sb_agblocks && block->bb_u.s.bb_rightsib != cpu_to_be32(NULLAGBLOCK))) return false; return true; } static void xfs_allocbt_read_verify( struct xfs_buf *bp) { if (!xfs_btree_sblock_verify_crc(bp)) xfs_buf_ioerror(bp, -EFSBADCRC); else if (!xfs_allocbt_verify(bp)) xfs_buf_ioerror(bp, -EFSCORRUPTED); if (bp->b_error) { trace_xfs_btree_corrupt(bp, _RET_IP_); xfs_verifier_error(bp); } } static void xfs_allocbt_write_verify( struct xfs_buf *bp) { if (!xfs_allocbt_verify(bp)) { trace_xfs_btree_corrupt(bp, _RET_IP_); xfs_buf_ioerror(bp, -EFSCORRUPTED); xfs_verifier_error(bp); return; } xfs_btree_sblock_calc_crc(bp); } const struct xfs_buf_ops xfs_allocbt_buf_ops = { .verify_read = xfs_allocbt_read_verify, .verify_write = xfs_allocbt_write_verify, }; #if defined(DEBUG) || defined(XFS_WARN) STATIC int xfs_allocbt_keys_inorder( struct xfs_btree_cur *cur, union xfs_btree_key *k1, union xfs_btree_key *k2) { if (cur->bc_btnum == XFS_BTNUM_BNO) { return be32_to_cpu(k1->alloc.ar_startblock) < be32_to_cpu(k2->alloc.ar_startblock); } else { return be32_to_cpu(k1->alloc.ar_blockcount) < be32_to_cpu(k2->alloc.ar_blockcount) || (k1->alloc.ar_blockcount == k2->alloc.ar_blockcount && be32_to_cpu(k1->alloc.ar_startblock) < be32_to_cpu(k2->alloc.ar_startblock)); } } STATIC int xfs_allocbt_recs_inorder( struct xfs_btree_cur *cur, union xfs_btree_rec *r1, union xfs_btree_rec *r2) { if (cur->bc_btnum == XFS_BTNUM_BNO) { return be32_to_cpu(r1->alloc.ar_startblock) + be32_to_cpu(r1->alloc.ar_blockcount) <= be32_to_cpu(r2->alloc.ar_startblock); } else { return be32_to_cpu(r1->alloc.ar_blockcount) < be32_to_cpu(r2->alloc.ar_blockcount) || (r1->alloc.ar_blockcount == r2->alloc.ar_blockcount && be32_to_cpu(r1->alloc.ar_startblock) < be32_to_cpu(r2->alloc.ar_startblock)); } } #endif /* DEBUG */ static const struct xfs_btree_ops xfs_allocbt_ops = { .rec_len = sizeof(xfs_alloc_rec_t), .key_len = sizeof(xfs_alloc_key_t), .dup_cursor = xfs_allocbt_dup_cursor, .set_root = xfs_allocbt_set_root, .alloc_block = xfs_allocbt_alloc_block, .free_block = xfs_allocbt_free_block, .update_lastrec = xfs_allocbt_update_lastrec, .get_minrecs = xfs_allocbt_get_minrecs, .get_maxrecs = xfs_allocbt_get_maxrecs, .init_key_from_rec = xfs_allocbt_init_key_from_rec, .init_rec_from_key = xfs_allocbt_init_rec_from_key, .init_rec_from_cur = xfs_allocbt_init_rec_from_cur, .init_ptr_from_cur = xfs_allocbt_init_ptr_from_cur, .key_diff = xfs_allocbt_key_diff, .buf_ops = &xfs_allocbt_buf_ops, #if defined(DEBUG) || defined(XFS_WARN) .keys_inorder = xfs_allocbt_keys_inorder, .recs_inorder = xfs_allocbt_recs_inorder, #endif }; /* * Allocate a new allocation btree cursor. */ struct xfs_btree_cur * /* new alloc btree cursor */ xfs_allocbt_init_cursor( struct xfs_mount *mp, /* file system mount point */ struct xfs_trans *tp, /* transaction pointer */ struct xfs_buf *agbp, /* buffer for agf structure */ xfs_agnumber_t agno, /* allocation group number */ xfs_btnum_t btnum) /* btree identifier */ { struct xfs_agf *agf = XFS_BUF_TO_AGF(agbp); struct xfs_btree_cur *cur; ASSERT(btnum == XFS_BTNUM_BNO || btnum == XFS_BTNUM_CNT); cur = kmem_zone_zalloc(xfs_btree_cur_zone, KM_SLEEP); cur->bc_tp = tp; cur->bc_mp = mp; cur->bc_btnum = btnum; cur->bc_blocklog = mp->m_sb.sb_blocklog; cur->bc_ops = &xfs_allocbt_ops; if (btnum == XFS_BTNUM_CNT) { cur->bc_nlevels = be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]); cur->bc_flags = XFS_BTREE_LASTREC_UPDATE; } else { cur->bc_nlevels = be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNO]); } cur->bc_private.a.agbp = agbp; cur->bc_private.a.agno = agno; if (xfs_sb_version_hascrc(&mp->m_sb)) cur->bc_flags |= XFS_BTREE_CRC_BLOCKS; return cur; } /* * Calculate number of records in an alloc btree block. */ int xfs_allocbt_maxrecs( struct xfs_mount *mp, int blocklen, int leaf) { blocklen -= XFS_ALLOC_BLOCK_LEN(mp); if (leaf) return blocklen / sizeof(xfs_alloc_rec_t); return blocklen / (sizeof(xfs_alloc_key_t) + sizeof(xfs_alloc_ptr_t)); } partclone-0.2.86/src/xfs/xfs_alloc_btree.h000066400000000000000000000037611262102574200205010ustar00rootroot00000000000000/* * Copyright (c) 2000,2005 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __XFS_ALLOC_BTREE_H__ #define __XFS_ALLOC_BTREE_H__ /* * Freespace on-disk structures */ struct xfs_buf; struct xfs_btree_cur; struct xfs_mount; /* * Btree block header size depends on a superblock flag. */ #define XFS_ALLOC_BLOCK_LEN(mp) \ (xfs_sb_version_hascrc(&((mp)->m_sb)) ? \ XFS_BTREE_SBLOCK_CRC_LEN : XFS_BTREE_SBLOCK_LEN) /* * Record, key, and pointer address macros for btree blocks. * * (note that some of these may appear unused, but they are used in userspace) */ #define XFS_ALLOC_REC_ADDR(mp, block, index) \ ((xfs_alloc_rec_t *) \ ((char *)(block) + \ XFS_ALLOC_BLOCK_LEN(mp) + \ (((index) - 1) * sizeof(xfs_alloc_rec_t)))) #define XFS_ALLOC_KEY_ADDR(mp, block, index) \ ((xfs_alloc_key_t *) \ ((char *)(block) + \ XFS_ALLOC_BLOCK_LEN(mp) + \ ((index) - 1) * sizeof(xfs_alloc_key_t))) #define XFS_ALLOC_PTR_ADDR(mp, block, index, maxrecs) \ ((xfs_alloc_ptr_t *) \ ((char *)(block) + \ XFS_ALLOC_BLOCK_LEN(mp) + \ (maxrecs) * sizeof(xfs_alloc_key_t) + \ ((index) - 1) * sizeof(xfs_alloc_ptr_t))) extern struct xfs_btree_cur *xfs_allocbt_init_cursor(struct xfs_mount *, struct xfs_trans *, struct xfs_buf *, xfs_agnumber_t, xfs_btnum_t); extern int xfs_allocbt_maxrecs(struct xfs_mount *, int, int); #endif /* __XFS_ALLOC_BTREE_H__ */ partclone-0.2.86/src/xfs/xfs_arch.h000066400000000000000000000201451262102574200171360ustar00rootroot00000000000000/* * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __XFS_ARCH_H__ #define __XFS_ARCH_H__ #if __BYTE_ORDER == __BIG_ENDIAN #define XFS_NATIVE_HOST 1 #else #undef XFS_NATIVE_HOST #endif #ifdef __CHECKER__ #define __bitwise __attribute__((bitwise)) #define __force __attribute__((force)) #else #define __bitwise #define __force #endif typedef __u16 __bitwise __le16; typedef __u32 __bitwise __le32; typedef __u64 __bitwise __le64; typedef __u16 __bitwise __be16; typedef __u32 __bitwise __be32; typedef __u64 __bitwise __be64; /* * Casts are necessary for constants, because we never know how for sure * how U/UL/ULL map to __u16, __u32, __u64. At least not in a portable way. */ #define ___swab16(x) \ ({ \ __u16 __x = (x); \ ((__u16)( \ (((__u16)(__x) & (__u16)0x00ffU) << 8) | \ (((__u16)(__x) & (__u16)0xff00U) >> 8) )); \ }) #define ___swab32(x) \ ({ \ __u32 __x = (x); \ ((__u32)( \ (((__u32)(__x) & (__u32)0x000000ffUL) << 24) | \ (((__u32)(__x) & (__u32)0x0000ff00UL) << 8) | \ (((__u32)(__x) & (__u32)0x00ff0000UL) >> 8) | \ (((__u32)(__x) & (__u32)0xff000000UL) >> 24) )); \ }) #define ___swab64(x) \ ({ \ __u64 __x = (x); \ ((__u64)( \ (__u64)(((__u64)(__x) & (__u64)0x00000000000000ffULL) << 56) | \ (__u64)(((__u64)(__x) & (__u64)0x000000000000ff00ULL) << 40) | \ (__u64)(((__u64)(__x) & (__u64)0x0000000000ff0000ULL) << 24) | \ (__u64)(((__u64)(__x) & (__u64)0x00000000ff000000ULL) << 8) | \ (__u64)(((__u64)(__x) & (__u64)0x000000ff00000000ULL) >> 8) | \ (__u64)(((__u64)(__x) & (__u64)0x0000ff0000000000ULL) >> 24) | \ (__u64)(((__u64)(__x) & (__u64)0x00ff000000000000ULL) >> 40) | \ (__u64)(((__u64)(__x) & (__u64)0xff00000000000000ULL) >> 56) )); \ }) #define ___constant_swab16(x) \ ((__u16)( \ (((__u16)(x) & (__u16)0x00ffU) << 8) | \ (((__u16)(x) & (__u16)0xff00U) >> 8) )) #define ___constant_swab32(x) \ ((__u32)( \ (((__u32)(x) & (__u32)0x000000ffUL) << 24) | \ (((__u32)(x) & (__u32)0x0000ff00UL) << 8) | \ (((__u32)(x) & (__u32)0x00ff0000UL) >> 8) | \ (((__u32)(x) & (__u32)0xff000000UL) >> 24) )) #define ___constant_swab64(x) \ ((__u64)( \ (__u64)(((__u64)(x) & (__u64)0x00000000000000ffULL) << 56) | \ (__u64)(((__u64)(x) & (__u64)0x000000000000ff00ULL) << 40) | \ (__u64)(((__u64)(x) & (__u64)0x0000000000ff0000ULL) << 24) | \ (__u64)(((__u64)(x) & (__u64)0x00000000ff000000ULL) << 8) | \ (__u64)(((__u64)(x) & (__u64)0x000000ff00000000ULL) >> 8) | \ (__u64)(((__u64)(x) & (__u64)0x0000ff0000000000ULL) >> 24) | \ (__u64)(((__u64)(x) & (__u64)0x00ff000000000000ULL) >> 40) | \ (__u64)(((__u64)(x) & (__u64)0xff00000000000000ULL) >> 56) )) /* * provide defaults when no architecture-specific optimization is detected */ #ifndef __arch__swab16 # define __arch__swab16(x) ({ __u16 __tmp = (x) ; ___swab16(__tmp); }) #endif #ifndef __arch__swab32 # define __arch__swab32(x) ({ __u32 __tmp = (x) ; ___swab32(__tmp); }) #endif #ifndef __arch__swab64 # define __arch__swab64(x) ({ __u64 __tmp = (x) ; ___swab64(__tmp); }) #endif #ifndef __arch__swab16p # define __arch__swab16p(x) __arch__swab16(*(x)) #endif #ifndef __arch__swab32p # define __arch__swab32p(x) __arch__swab32(*(x)) #endif #ifndef __arch__swab64p # define __arch__swab64p(x) __arch__swab64(*(x)) #endif #ifndef __arch__swab16s # define __arch__swab16s(x) do { *(x) = __arch__swab16p((x)); } while (0) #endif #ifndef __arch__swab32s # define __arch__swab32s(x) do { *(x) = __arch__swab32p((x)); } while (0) #endif #ifndef __arch__swab64s # define __arch__swab64s(x) do { *(x) = __arch__swab64p((x)); } while (0) #endif /* * Allow constant folding */ # define __swab16(x) \ (__builtin_constant_p((__u16)(x)) ? \ ___constant_swab16((x)) : \ __fswab16((x))) # define __swab32(x) \ (__builtin_constant_p((__u32)(x)) ? \ ___constant_swab32((x)) : \ __fswab32((x))) # define __swab64(x) \ (__builtin_constant_p((__u64)(x)) ? \ ___constant_swab64((x)) : \ __fswab64((x))) static __inline__ __u16 __fswab16(__u16 x) { return (__extension__ __arch__swab16(x)); } static __inline__ __u16 __swab16p(__u16 *x) { return (__extension__ __arch__swab16p(x)); } static __inline__ void __swab16s(__u16 *addr) { (__extension__ ({__arch__swab16s(addr);})); } static __inline__ __u32 __fswab32(__u32 x) { return (__extension__ __arch__swab32(x)); } static __inline__ __u32 __swab32p(__u32 *x) { return (__extension__ __arch__swab32p(x)); } static __inline__ void __swab32s(__u32 *addr) { (__extension__ ({__arch__swab32s(addr);})); } static __inline__ __u64 __fswab64(__u64 x) { # ifdef __SWAB_64_THRU_32__ __u32 h = x >> 32; __u32 l = x & ((1ULL<<32)-1); return (((__u64)__swab32(l)) << 32) | ((__u64)(__swab32(h))); # else return (__extension__ __arch__swab64(x)); # endif } static __inline__ __u64 __swab64p(__u64 *x) { return (__extension__ __arch__swab64p(x)); } static __inline__ void __swab64s(__u64 *addr) { (__extension__ ({__arch__swab64s(addr);})); } #ifdef XFS_NATIVE_HOST #define cpu_to_be16(val) ((__force __be16)(__u16)(val)) #define cpu_to_be32(val) ((__force __be32)(__u32)(val)) #define cpu_to_be64(val) ((__force __be64)(__u64)(val)) #define be16_to_cpu(val) ((__force __u16)(__be16)(val)) #define be32_to_cpu(val) ((__force __u32)(__be32)(val)) #define be64_to_cpu(val) ((__force __u64)(__be64)(val)) #define cpu_to_le32(val) ((__force __be32)__swab32((__u32)(val))) #define le32_to_cpu(val) (__swab32((__force __u32)(__le32)(val))) #define __constant_cpu_to_le32(val) \ ((__force __le32)___constant_swab32((__u32)(val))) #define __constant_cpu_to_be32(val) \ ((__force __be32)(__u32)(val)) #else #define cpu_to_be16(val) ((__force __be16)__swab16((__u16)(val))) #define cpu_to_be32(val) ((__force __be32)__swab32((__u32)(val))) #define cpu_to_be64(val) ((__force __be64)__swab64((__u64)(val))) #define be16_to_cpu(val) (__swab16((__force __u16)(__be16)(val))) #define be32_to_cpu(val) (__swab32((__force __u32)(__be32)(val))) #define be64_to_cpu(val) (__swab64((__force __u64)(__be64)(val))) #define cpu_to_le32(val) ((__force __le32)(__u32)(val)) #define le32_to_cpu(val) ((__force __u32)(__le32)(val)) #define __constant_cpu_to_le32(val) \ ((__force __le32)(__u32)(val)) #define __constant_cpu_to_be32(val) \ ((__force __be32)___constant_swab32((__u32)(val))) #endif static inline void be16_add_cpu(__be16 *a, __s16 b) { *a = cpu_to_be16(be16_to_cpu(*a) + b); } static inline void be32_add_cpu(__be32 *a, __s32 b) { *a = cpu_to_be32(be32_to_cpu(*a) + b); } static inline void be64_add_cpu(__be64 *a, __s64 b) { *a = cpu_to_be64(be64_to_cpu(*a) + b); } static inline __uint16_t get_unaligned_be16(void *p) { __uint8_t *__p = p; return __p[0] << 8 | __p[1]; } static inline __uint32_t get_unaligned_be32(void *p) { __uint8_t *__p = p; return __p[0] << 24 | __p[1] << 16 | __p[2] << 8 | __p[3]; } static inline __uint64_t get_unaligned_be64(void *p) { return (__uint64_t)get_unaligned_be32(p) << 32 | get_unaligned_be32(p + 4); } static inline void put_unaligned_be16(__uint16_t val, void *p) { __uint8_t *__p = p; *__p++ = val >> 8; *__p++ = val; } static inline void put_unaligned_be32(__uint32_t val, void *p) { __uint8_t *__p = p; put_unaligned_be16(val >> 16, __p); put_unaligned_be16(val, __p + 2); } static inline void put_unaligned_be64(__uint64_t val, void *p) { put_unaligned_be32(val >> 32, p); put_unaligned_be32(val, p + 4); } /* ARM old ABI has some weird alignment/padding */ #if defined(__arm__) && !defined(__ARM_EABI__) #define __arch_pack __attribute__((packed)) #else #define __arch_pack #endif #endif /* __XFS_ARCH_H__ */ partclone-0.2.86/src/xfs/xfs_attr.c000066400000000000000000001101551262102574200171670ustar00rootroot00000000000000/* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_bit.h" #include "xfs_mount.h" #include "xfs_da_format.h" #include "xfs_da_btree.h" #include "xfs_attr_sf.h" #include "xfs_inode.h" #include "xfs_alloc.h" #include "xfs_trans.h" #include "xfs_bmap.h" #include "xfs_bmap_btree.h" #include "xfs_attr_leaf.h" #include "xfs_attr_remote.h" #include "xfs_trans_space.h" #include "xfs_trace.h" /* * xfs_attr.c * * Provide the external interfaces to manage attribute lists. */ /*======================================================================== * Function prototypes for the kernel. *========================================================================*/ /* * Internal routines when attribute list fits inside the inode. */ STATIC int xfs_attr_shortform_addname(xfs_da_args_t *args); /* * Internal routines when attribute list is one block. */ STATIC int xfs_attr_leaf_get(xfs_da_args_t *args); STATIC int xfs_attr_leaf_addname(xfs_da_args_t *args); STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args); /* * Internal routines when attribute list is more than one block. */ STATIC int xfs_attr_node_get(xfs_da_args_t *args); STATIC int xfs_attr_node_addname(xfs_da_args_t *args); STATIC int xfs_attr_node_removename(xfs_da_args_t *args); STATIC int xfs_attr_fillstate(xfs_da_state_t *state); STATIC int xfs_attr_refillstate(xfs_da_state_t *state); STATIC int xfs_attr_args_init( struct xfs_da_args *args, struct xfs_inode *dp, const unsigned char *name, int flags) { if (!name) return -EINVAL; memset(args, 0, sizeof(*args)); args->geo = dp->i_mount->m_attr_geo; args->whichfork = XFS_ATTR_FORK; args->dp = dp; args->flags = flags; args->name = name; args->namelen = strlen((const char *)name); if (args->namelen >= MAXNAMELEN) return -EFAULT; /* match IRIX behaviour */ args->hashval = xfs_da_hashname(args->name, args->namelen); return 0; } int xfs_inode_hasattr( struct xfs_inode *ip) { if (!XFS_IFORK_Q(ip) || (ip->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS && ip->i_d.di_anextents == 0)) return 0; return 1; } /*======================================================================== * Overall external interface routines. *========================================================================*/ int xfs_attr_get( struct xfs_inode *ip, const unsigned char *name, unsigned char *value, int *valuelenp, int flags) { struct xfs_da_args args; uint lock_mode; int error; XFS_STATS_INC(xs_attr_get); if (XFS_FORCED_SHUTDOWN(ip->i_mount)) return -EIO; if (!xfs_inode_hasattr(ip)) return -ENOATTR; error = xfs_attr_args_init(&args, ip, name, flags); if (error) return error; args.value = value; args.valuelen = *valuelenp; lock_mode = xfs_ilock_attr_map_shared(ip); if (!xfs_inode_hasattr(ip)) error = -ENOATTR; else if (ip->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) error = xfs_attr_shortform_getvalue(&args); else if (xfs_bmap_one_block(ip, XFS_ATTR_FORK)) error = xfs_attr_leaf_get(&args); else error = xfs_attr_node_get(&args); xfs_iunlock(ip, lock_mode); *valuelenp = args.valuelen; return error == -EEXIST ? 0 : error; } /* * Calculate how many blocks we need for the new attribute, */ STATIC int xfs_attr_calc_size( struct xfs_da_args *args, int *local) { struct xfs_mount *mp = args->dp->i_mount; int size; int nblks; /* * Determine space new attribute will use, and if it would be * "local" or "remote" (note: local != inline). */ size = xfs_attr_leaf_newentsize(args, local); nblks = XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK); if (*local) { if (size > (args->geo->blksize / 2)) { /* Double split possible */ nblks *= 2; } } else { /* * Out of line attribute, cannot double split, but * make room for the attribute value itself. */ uint dblocks = xfs_attr3_rmt_blocks(mp, args->valuelen); nblks += dblocks; nblks += XFS_NEXTENTADD_SPACE_RES(mp, dblocks, XFS_ATTR_FORK); } return nblks; } int xfs_attr_set( struct xfs_inode *dp, const unsigned char *name, unsigned char *value, int valuelen, int flags) { struct xfs_mount *mp = dp->i_mount; struct xfs_da_args args; struct xfs_bmap_free flist; struct xfs_trans_res tres; xfs_fsblock_t firstblock; int rsvd = (flags & ATTR_ROOT) != 0; int error, err2, committed, local; XFS_STATS_INC(xs_attr_set); if (XFS_FORCED_SHUTDOWN(dp->i_mount)) return -EIO; error = xfs_attr_args_init(&args, dp, name, flags); if (error) return error; args.value = value; args.valuelen = valuelen; args.firstblock = &firstblock; args.flist = &flist; args.op_flags = XFS_DA_OP_ADDNAME | XFS_DA_OP_OKNOENT; args.total = xfs_attr_calc_size(&args, &local); error = xfs_qm_dqattach(dp, 0); if (error) return error; /* * If the inode doesn't have an attribute fork, add one. * (inode must not be locked when we call this routine) */ if (XFS_IFORK_Q(dp) == 0) { int sf_size = sizeof(xfs_attr_sf_hdr_t) + XFS_ATTR_SF_ENTSIZE_BYNAME(args.namelen, valuelen); error = xfs_bmap_add_attrfork(dp, sf_size, rsvd); if (error) return error; } /* * Start our first transaction of the day. * * All future transactions during this code must be "chained" off * this one via the trans_dup() call. All transactions will contain * the inode, and the inode will always be marked with trans_ihold(). * Since the inode will be locked in all transactions, we must log * the inode in every transaction to let it float upward through * the log. */ args.trans = xfs_trans_alloc(mp, XFS_TRANS_ATTR_SET); /* * Root fork attributes can use reserved data blocks for this * operation if necessary */ if (rsvd) args.trans->t_flags |= XFS_TRANS_RESERVE; tres.tr_logres = M_RES(mp)->tr_attrsetm.tr_logres + M_RES(mp)->tr_attrsetrt.tr_logres * args.total; tres.tr_logcount = XFS_ATTRSET_LOG_COUNT; tres.tr_logflags = XFS_TRANS_PERM_LOG_RES; error = xfs_trans_reserve(args.trans, &tres, args.total, 0); if (error) { xfs_trans_cancel(args.trans); return error; } xfs_ilock(dp, XFS_ILOCK_EXCL); error = xfs_trans_reserve_quota_nblks(args.trans, dp, args.total, 0, rsvd ? XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_FORCE_RES : XFS_QMOPT_RES_REGBLKS); if (error) { xfs_iunlock(dp, XFS_ILOCK_EXCL); xfs_trans_cancel(args.trans); return error; } xfs_trans_ijoin(args.trans, dp, 0); /* * If the attribute list is non-existent or a shortform list, * upgrade it to a single-leaf-block attribute list. */ if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL || (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS && dp->i_d.di_anextents == 0)) { /* * Build initial attribute list (if required). */ if (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS) xfs_attr_shortform_create(&args); /* * Try to add the attr to the attribute list in * the inode. */ error = xfs_attr_shortform_addname(&args); if (error != -ENOSPC) { /* * Commit the shortform mods, and we're done. * NOTE: this is also the error path (EEXIST, etc). */ ASSERT(args.trans != NULL); /* * If this is a synchronous mount, make sure that * the transaction goes to disk before returning * to the user. */ if (mp->m_flags & XFS_MOUNT_WSYNC) xfs_trans_set_sync(args.trans); if (!error && (flags & ATTR_KERNOTIME) == 0) { xfs_trans_ichgtime(args.trans, dp, XFS_ICHGTIME_CHG); } err2 = xfs_trans_commit(args.trans); xfs_iunlock(dp, XFS_ILOCK_EXCL); return error ? error : err2; } /* * It won't fit in the shortform, transform to a leaf block. * GROT: another possible req'mt for a double-split btree op. */ xfs_bmap_init(args.flist, args.firstblock); error = xfs_attr_shortform_to_leaf(&args); if (!error) { error = xfs_bmap_finish(&args.trans, args.flist, &committed); } if (error) { ASSERT(committed); args.trans = NULL; xfs_bmap_cancel(&flist); goto out; } /* * bmap_finish() may have committed the last trans and started * a new one. We need the inode to be in all transactions. */ if (committed) xfs_trans_ijoin(args.trans, dp, 0); /* * Commit the leaf transformation. We'll need another (linked) * transaction to add the new attribute to the leaf. */ error = xfs_trans_roll(&args.trans, dp); if (error) goto out; } if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) error = xfs_attr_leaf_addname(&args); else error = xfs_attr_node_addname(&args); if (error) goto out; /* * If this is a synchronous mount, make sure that the * transaction goes to disk before returning to the user. */ if (mp->m_flags & XFS_MOUNT_WSYNC) xfs_trans_set_sync(args.trans); if ((flags & ATTR_KERNOTIME) == 0) xfs_trans_ichgtime(args.trans, dp, XFS_ICHGTIME_CHG); /* * Commit the last in the sequence of transactions. */ xfs_trans_log_inode(args.trans, dp, XFS_ILOG_CORE); error = xfs_trans_commit(args.trans); xfs_iunlock(dp, XFS_ILOCK_EXCL); return error; out: if (args.trans) xfs_trans_cancel(args.trans); xfs_iunlock(dp, XFS_ILOCK_EXCL); return error; } /* * Generic handler routine to remove a name from an attribute list. * Transitions attribute list from Btree to shortform as necessary. */ int xfs_attr_remove( struct xfs_inode *dp, const unsigned char *name, int flags) { struct xfs_mount *mp = dp->i_mount; struct xfs_da_args args; struct xfs_bmap_free flist; xfs_fsblock_t firstblock; int error; XFS_STATS_INC(xs_attr_remove); if (XFS_FORCED_SHUTDOWN(dp->i_mount)) return -EIO; if (!xfs_inode_hasattr(dp)) return -ENOATTR; error = xfs_attr_args_init(&args, dp, name, flags); if (error) return error; args.firstblock = &firstblock; args.flist = &flist; /* * we have no control over the attribute names that userspace passes us * to remove, so we have to allow the name lookup prior to attribute * removal to fail. */ args.op_flags = XFS_DA_OP_OKNOENT; error = xfs_qm_dqattach(dp, 0); if (error) return error; /* * Start our first transaction of the day. * * All future transactions during this code must be "chained" off * this one via the trans_dup() call. All transactions will contain * the inode, and the inode will always be marked with trans_ihold(). * Since the inode will be locked in all transactions, we must log * the inode in every transaction to let it float upward through * the log. */ args.trans = xfs_trans_alloc(mp, XFS_TRANS_ATTR_RM); /* * Root fork attributes can use reserved data blocks for this * operation if necessary */ if (flags & ATTR_ROOT) args.trans->t_flags |= XFS_TRANS_RESERVE; error = xfs_trans_reserve(args.trans, &M_RES(mp)->tr_attrrm, XFS_ATTRRM_SPACE_RES(mp), 0); if (error) { xfs_trans_cancel(args.trans); return error; } xfs_ilock(dp, XFS_ILOCK_EXCL); /* * No need to make quota reservations here. We expect to release some * blocks not allocate in the common case. */ xfs_trans_ijoin(args.trans, dp, 0); if (!xfs_inode_hasattr(dp)) { error = -ENOATTR; } else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) { ASSERT(dp->i_afp->if_flags & XFS_IFINLINE); error = xfs_attr_shortform_remove(&args); } else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) { error = xfs_attr_leaf_removename(&args); } else { error = xfs_attr_node_removename(&args); } if (error) goto out; /* * If this is a synchronous mount, make sure that the * transaction goes to disk before returning to the user. */ if (mp->m_flags & XFS_MOUNT_WSYNC) xfs_trans_set_sync(args.trans); if ((flags & ATTR_KERNOTIME) == 0) xfs_trans_ichgtime(args.trans, dp, XFS_ICHGTIME_CHG); /* * Commit the last in the sequence of transactions. */ xfs_trans_log_inode(args.trans, dp, XFS_ILOG_CORE); error = xfs_trans_commit(args.trans); xfs_iunlock(dp, XFS_ILOCK_EXCL); return error; out: if (args.trans) xfs_trans_cancel(args.trans); xfs_iunlock(dp, XFS_ILOCK_EXCL); return error; } /*======================================================================== * External routines when attribute list is inside the inode *========================================================================*/ /* * Add a name to the shortform attribute list structure * This is the external routine. */ STATIC int xfs_attr_shortform_addname(xfs_da_args_t *args) { int newsize, forkoff, retval; trace_xfs_attr_sf_addname(args); retval = xfs_attr_shortform_lookup(args); if ((args->flags & ATTR_REPLACE) && (retval == -ENOATTR)) { return retval; } else if (retval == -EEXIST) { if (args->flags & ATTR_CREATE) return retval; retval = xfs_attr_shortform_remove(args); ASSERT(retval == 0); } if (args->namelen >= XFS_ATTR_SF_ENTSIZE_MAX || args->valuelen >= XFS_ATTR_SF_ENTSIZE_MAX) return -ENOSPC; newsize = XFS_ATTR_SF_TOTSIZE(args->dp); newsize += XFS_ATTR_SF_ENTSIZE_BYNAME(args->namelen, args->valuelen); forkoff = xfs_attr_shortform_bytesfit(args->dp, newsize); if (!forkoff) return -ENOSPC; xfs_attr_shortform_add(args, forkoff); return 0; } /*======================================================================== * External routines when attribute list is one block *========================================================================*/ /* * Add a name to the leaf attribute list structure * * This leaf block cannot have a "remote" value, we only call this routine * if bmap_one_block() says there is only one block (ie: no remote blks). */ STATIC int xfs_attr_leaf_addname(xfs_da_args_t *args) { xfs_inode_t *dp; struct xfs_buf *bp; int retval, error, committed, forkoff; trace_xfs_attr_leaf_addname(args); /* * Read the (only) block in the attribute list in. */ dp = args->dp; args->blkno = 0; error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp); if (error) return error; /* * Look up the given attribute in the leaf block. Figure out if * the given flags produce an error or call for an atomic rename. */ retval = xfs_attr3_leaf_lookup_int(bp, args); if ((args->flags & ATTR_REPLACE) && (retval == -ENOATTR)) { xfs_trans_brelse(args->trans, bp); return retval; } else if (retval == -EEXIST) { if (args->flags & ATTR_CREATE) { /* pure create op */ xfs_trans_brelse(args->trans, bp); return retval; } trace_xfs_attr_leaf_replace(args); /* save the attribute state for later removal*/ args->op_flags |= XFS_DA_OP_RENAME; /* an atomic rename */ args->blkno2 = args->blkno; /* set 2nd entry info*/ args->index2 = args->index; args->rmtblkno2 = args->rmtblkno; args->rmtblkcnt2 = args->rmtblkcnt; args->rmtvaluelen2 = args->rmtvaluelen; /* * clear the remote attr state now that it is saved so that the * values reflect the state of the attribute we are about to * add, not the attribute we just found and will remove later. */ args->rmtblkno = 0; args->rmtblkcnt = 0; args->rmtvaluelen = 0; } /* * Add the attribute to the leaf block, transitioning to a Btree * if required. */ retval = xfs_attr3_leaf_add(bp, args); if (retval == -ENOSPC) { /* * Promote the attribute list to the Btree format, then * Commit that transaction so that the node_addname() call * can manage its own transactions. */ xfs_bmap_init(args->flist, args->firstblock); error = xfs_attr3_leaf_to_node(args); if (!error) { error = xfs_bmap_finish(&args->trans, args->flist, &committed); } if (error) { ASSERT(committed); args->trans = NULL; xfs_bmap_cancel(args->flist); return error; } /* * bmap_finish() may have committed the last trans and started * a new one. We need the inode to be in all transactions. */ if (committed) xfs_trans_ijoin(args->trans, dp, 0); /* * Commit the current trans (including the inode) and start * a new one. */ error = xfs_trans_roll(&args->trans, dp); if (error) return error; /* * Fob the whole rest of the problem off on the Btree code. */ error = xfs_attr_node_addname(args); return error; } /* * Commit the transaction that added the attr name so that * later routines can manage their own transactions. */ error = xfs_trans_roll(&args->trans, dp); if (error) return error; /* * If there was an out-of-line value, allocate the blocks we * identified for its storage and copy the value. This is done * after we create the attribute so that we don't overflow the * maximum size of a transaction and/or hit a deadlock. */ if (args->rmtblkno > 0) { error = xfs_attr_rmtval_set(args); if (error) return error; } /* * If this is an atomic rename operation, we must "flip" the * incomplete flags on the "new" and "old" attribute/value pairs * so that one disappears and one appears atomically. Then we * must remove the "old" attribute/value pair. */ if (args->op_flags & XFS_DA_OP_RENAME) { /* * In a separate transaction, set the incomplete flag on the * "old" attr and clear the incomplete flag on the "new" attr. */ error = xfs_attr3_leaf_flipflags(args); if (error) return error; /* * Dismantle the "old" attribute/value pair by removing * a "remote" value (if it exists). */ args->index = args->index2; args->blkno = args->blkno2; args->rmtblkno = args->rmtblkno2; args->rmtblkcnt = args->rmtblkcnt2; args->rmtvaluelen = args->rmtvaluelen2; if (args->rmtblkno) { error = xfs_attr_rmtval_remove(args); if (error) return error; } /* * Read in the block containing the "old" attr, then * remove the "old" attr from that block (neat, huh!) */ error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp); if (error) return error; xfs_attr3_leaf_remove(bp, args); /* * If the result is small enough, shrink it all into the inode. */ if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) { xfs_bmap_init(args->flist, args->firstblock); error = xfs_attr3_leaf_to_shortform(bp, args, forkoff); /* bp is gone due to xfs_da_shrink_inode */ if (!error) { error = xfs_bmap_finish(&args->trans, args->flist, &committed); } if (error) { ASSERT(committed); args->trans = NULL; xfs_bmap_cancel(args->flist); return error; } /* * bmap_finish() may have committed the last trans * and started a new one. We need the inode to be * in all transactions. */ if (committed) xfs_trans_ijoin(args->trans, dp, 0); } /* * Commit the remove and start the next trans in series. */ error = xfs_trans_roll(&args->trans, dp); } else if (args->rmtblkno > 0) { /* * Added a "remote" value, just clear the incomplete flag. */ error = xfs_attr3_leaf_clearflag(args); } return error; } /* * Remove a name from the leaf attribute list structure * * This leaf block cannot have a "remote" value, we only call this routine * if bmap_one_block() says there is only one block (ie: no remote blks). */ STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args) { xfs_inode_t *dp; struct xfs_buf *bp; int error, committed, forkoff; trace_xfs_attr_leaf_removename(args); /* * Remove the attribute. */ dp = args->dp; args->blkno = 0; error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp); if (error) return error; error = xfs_attr3_leaf_lookup_int(bp, args); if (error == -ENOATTR) { xfs_trans_brelse(args->trans, bp); return error; } xfs_attr3_leaf_remove(bp, args); /* * If the result is small enough, shrink it all into the inode. */ if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) { xfs_bmap_init(args->flist, args->firstblock); error = xfs_attr3_leaf_to_shortform(bp, args, forkoff); /* bp is gone due to xfs_da_shrink_inode */ if (!error) { error = xfs_bmap_finish(&args->trans, args->flist, &committed); } if (error) { ASSERT(committed); args->trans = NULL; xfs_bmap_cancel(args->flist); return error; } /* * bmap_finish() may have committed the last trans and started * a new one. We need the inode to be in all transactions. */ if (committed) xfs_trans_ijoin(args->trans, dp, 0); } return 0; } /* * Look up a name in a leaf attribute list structure. * * This leaf block cannot have a "remote" value, we only call this routine * if bmap_one_block() says there is only one block (ie: no remote blks). */ STATIC int xfs_attr_leaf_get(xfs_da_args_t *args) { struct xfs_buf *bp; int error; trace_xfs_attr_leaf_get(args); args->blkno = 0; error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp); if (error) return error; error = xfs_attr3_leaf_lookup_int(bp, args); if (error != -EEXIST) { xfs_trans_brelse(args->trans, bp); return error; } error = xfs_attr3_leaf_getvalue(bp, args); xfs_trans_brelse(args->trans, bp); if (!error && (args->rmtblkno > 0) && !(args->flags & ATTR_KERNOVAL)) { error = xfs_attr_rmtval_get(args); } return error; } /*======================================================================== * External routines when attribute list size > geo->blksize *========================================================================*/ /* * Add a name to a Btree-format attribute list. * * This will involve walking down the Btree, and may involve splitting * leaf nodes and even splitting intermediate nodes up to and including * the root node (a special case of an intermediate node). * * "Remote" attribute values confuse the issue and atomic rename operations * add a whole extra layer of confusion on top of that. */ STATIC int xfs_attr_node_addname(xfs_da_args_t *args) { xfs_da_state_t *state; xfs_da_state_blk_t *blk; xfs_inode_t *dp; xfs_mount_t *mp; int committed, retval, error; trace_xfs_attr_node_addname(args); /* * Fill in bucket of arguments/results/context to carry around. */ dp = args->dp; mp = dp->i_mount; restart: state = xfs_da_state_alloc(); state->args = args; state->mp = mp; /* * Search to see if name already exists, and get back a pointer * to where it should go. */ error = xfs_da3_node_lookup_int(state, &retval); if (error) goto out; blk = &state->path.blk[ state->path.active-1 ]; ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC); if ((args->flags & ATTR_REPLACE) && (retval == -ENOATTR)) { goto out; } else if (retval == -EEXIST) { if (args->flags & ATTR_CREATE) goto out; trace_xfs_attr_node_replace(args); /* save the attribute state for later removal*/ args->op_flags |= XFS_DA_OP_RENAME; /* atomic rename op */ args->blkno2 = args->blkno; /* set 2nd entry info*/ args->index2 = args->index; args->rmtblkno2 = args->rmtblkno; args->rmtblkcnt2 = args->rmtblkcnt; args->rmtvaluelen2 = args->rmtvaluelen; /* * clear the remote attr state now that it is saved so that the * values reflect the state of the attribute we are about to * add, not the attribute we just found and will remove later. */ args->rmtblkno = 0; args->rmtblkcnt = 0; args->rmtvaluelen = 0; } retval = xfs_attr3_leaf_add(blk->bp, state->args); if (retval == -ENOSPC) { if (state->path.active == 1) { /* * Its really a single leaf node, but it had * out-of-line values so it looked like it *might* * have been a b-tree. */ xfs_da_state_free(state); state = NULL; xfs_bmap_init(args->flist, args->firstblock); error = xfs_attr3_leaf_to_node(args); if (!error) { error = xfs_bmap_finish(&args->trans, args->flist, &committed); } if (error) { ASSERT(committed); args->trans = NULL; xfs_bmap_cancel(args->flist); goto out; } /* * bmap_finish() may have committed the last trans * and started a new one. We need the inode to be * in all transactions. */ if (committed) xfs_trans_ijoin(args->trans, dp, 0); /* * Commit the node conversion and start the next * trans in the chain. */ error = xfs_trans_roll(&args->trans, dp); if (error) goto out; goto restart; } /* * Split as many Btree elements as required. * This code tracks the new and old attr's location * in the index/blkno/rmtblkno/rmtblkcnt fields and * in the index2/blkno2/rmtblkno2/rmtblkcnt2 fields. */ xfs_bmap_init(args->flist, args->firstblock); error = xfs_da3_split(state); if (!error) { error = xfs_bmap_finish(&args->trans, args->flist, &committed); } if (error) { ASSERT(committed); args->trans = NULL; xfs_bmap_cancel(args->flist); goto out; } /* * bmap_finish() may have committed the last trans and started * a new one. We need the inode to be in all transactions. */ if (committed) xfs_trans_ijoin(args->trans, dp, 0); } else { /* * Addition succeeded, update Btree hashvals. */ xfs_da3_fixhashpath(state, &state->path); } /* * Kill the state structure, we're done with it and need to * allow the buffers to come back later. */ xfs_da_state_free(state); state = NULL; /* * Commit the leaf addition or btree split and start the next * trans in the chain. */ error = xfs_trans_roll(&args->trans, dp); if (error) goto out; /* * If there was an out-of-line value, allocate the blocks we * identified for its storage and copy the value. This is done * after we create the attribute so that we don't overflow the * maximum size of a transaction and/or hit a deadlock. */ if (args->rmtblkno > 0) { error = xfs_attr_rmtval_set(args); if (error) return error; } /* * If this is an atomic rename operation, we must "flip" the * incomplete flags on the "new" and "old" attribute/value pairs * so that one disappears and one appears atomically. Then we * must remove the "old" attribute/value pair. */ if (args->op_flags & XFS_DA_OP_RENAME) { /* * In a separate transaction, set the incomplete flag on the * "old" attr and clear the incomplete flag on the "new" attr. */ error = xfs_attr3_leaf_flipflags(args); if (error) goto out; /* * Dismantle the "old" attribute/value pair by removing * a "remote" value (if it exists). */ args->index = args->index2; args->blkno = args->blkno2; args->rmtblkno = args->rmtblkno2; args->rmtblkcnt = args->rmtblkcnt2; args->rmtvaluelen = args->rmtvaluelen2; if (args->rmtblkno) { error = xfs_attr_rmtval_remove(args); if (error) return error; } /* * Re-find the "old" attribute entry after any split ops. * The INCOMPLETE flag means that we will find the "old" * attr, not the "new" one. */ args->flags |= XFS_ATTR_INCOMPLETE; state = xfs_da_state_alloc(); state->args = args; state->mp = mp; state->inleaf = 0; error = xfs_da3_node_lookup_int(state, &retval); if (error) goto out; /* * Remove the name and update the hashvals in the tree. */ blk = &state->path.blk[ state->path.active-1 ]; ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC); error = xfs_attr3_leaf_remove(blk->bp, args); xfs_da3_fixhashpath(state, &state->path); /* * Check to see if the tree needs to be collapsed. */ if (retval && (state->path.active > 1)) { xfs_bmap_init(args->flist, args->firstblock); error = xfs_da3_join(state); if (!error) { error = xfs_bmap_finish(&args->trans, args->flist, &committed); } if (error) { ASSERT(committed); args->trans = NULL; xfs_bmap_cancel(args->flist); goto out; } /* * bmap_finish() may have committed the last trans * and started a new one. We need the inode to be * in all transactions. */ if (committed) xfs_trans_ijoin(args->trans, dp, 0); } /* * Commit and start the next trans in the chain. */ error = xfs_trans_roll(&args->trans, dp); if (error) goto out; } else if (args->rmtblkno > 0) { /* * Added a "remote" value, just clear the incomplete flag. */ error = xfs_attr3_leaf_clearflag(args); if (error) goto out; } retval = error = 0; out: if (state) xfs_da_state_free(state); if (error) return error; return retval; } /* * Remove a name from a B-tree attribute list. * * This will involve walking down the Btree, and may involve joining * leaf nodes and even joining intermediate nodes up to and including * the root node (a special case of an intermediate node). */ STATIC int xfs_attr_node_removename(xfs_da_args_t *args) { xfs_da_state_t *state; xfs_da_state_blk_t *blk; xfs_inode_t *dp; struct xfs_buf *bp; int retval, error, committed, forkoff; trace_xfs_attr_node_removename(args); /* * Tie a string around our finger to remind us where we are. */ dp = args->dp; state = xfs_da_state_alloc(); state->args = args; state->mp = dp->i_mount; /* * Search to see if name exists, and get back a pointer to it. */ error = xfs_da3_node_lookup_int(state, &retval); if (error || (retval != -EEXIST)) { if (error == 0) error = retval; goto out; } /* * If there is an out-of-line value, de-allocate the blocks. * This is done before we remove the attribute so that we don't * overflow the maximum size of a transaction and/or hit a deadlock. */ blk = &state->path.blk[ state->path.active-1 ]; ASSERT(blk->bp != NULL); ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC); if (args->rmtblkno > 0) { /* * Fill in disk block numbers in the state structure * so that we can get the buffers back after we commit * several transactions in the following calls. */ error = xfs_attr_fillstate(state); if (error) goto out; /* * Mark the attribute as INCOMPLETE, then bunmapi() the * remote value. */ error = xfs_attr3_leaf_setflag(args); if (error) goto out; error = xfs_attr_rmtval_remove(args); if (error) goto out; /* * Refill the state structure with buffers, the prior calls * released our buffers. */ error = xfs_attr_refillstate(state); if (error) goto out; } /* * Remove the name and update the hashvals in the tree. */ blk = &state->path.blk[ state->path.active-1 ]; ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC); retval = xfs_attr3_leaf_remove(blk->bp, args); xfs_da3_fixhashpath(state, &state->path); /* * Check to see if the tree needs to be collapsed. */ if (retval && (state->path.active > 1)) { xfs_bmap_init(args->flist, args->firstblock); error = xfs_da3_join(state); if (!error) { error = xfs_bmap_finish(&args->trans, args->flist, &committed); } if (error) { ASSERT(committed); args->trans = NULL; xfs_bmap_cancel(args->flist); goto out; } /* * bmap_finish() may have committed the last trans and started * a new one. We need the inode to be in all transactions. */ if (committed) xfs_trans_ijoin(args->trans, dp, 0); /* * Commit the Btree join operation and start a new trans. */ error = xfs_trans_roll(&args->trans, dp); if (error) goto out; } /* * If the result is small enough, push it all into the inode. */ if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) { /* * Have to get rid of the copy of this dabuf in the state. */ ASSERT(state->path.active == 1); ASSERT(state->path.blk[0].bp); state->path.blk[0].bp = NULL; error = xfs_attr3_leaf_read(args->trans, args->dp, 0, -1, &bp); if (error) goto out; if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) { xfs_bmap_init(args->flist, args->firstblock); error = xfs_attr3_leaf_to_shortform(bp, args, forkoff); /* bp is gone due to xfs_da_shrink_inode */ if (!error) { error = xfs_bmap_finish(&args->trans, args->flist, &committed); } if (error) { ASSERT(committed); args->trans = NULL; xfs_bmap_cancel(args->flist); goto out; } /* * bmap_finish() may have committed the last trans * and started a new one. We need the inode to be * in all transactions. */ if (committed) xfs_trans_ijoin(args->trans, dp, 0); } else xfs_trans_brelse(args->trans, bp); } error = 0; out: xfs_da_state_free(state); return error; } /* * Fill in the disk block numbers in the state structure for the buffers * that are attached to the state structure. * This is done so that we can quickly reattach ourselves to those buffers * after some set of transaction commits have released these buffers. */ STATIC int xfs_attr_fillstate(xfs_da_state_t *state) { xfs_da_state_path_t *path; xfs_da_state_blk_t *blk; int level; trace_xfs_attr_fillstate(state->args); /* * Roll down the "path" in the state structure, storing the on-disk * block number for those buffers in the "path". */ path = &state->path; ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH)); for (blk = path->blk, level = 0; level < path->active; blk++, level++) { if (blk->bp) { blk->disk_blkno = XFS_BUF_ADDR(blk->bp); blk->bp = NULL; } else { blk->disk_blkno = 0; } } /* * Roll down the "altpath" in the state structure, storing the on-disk * block number for those buffers in the "altpath". */ path = &state->altpath; ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH)); for (blk = path->blk, level = 0; level < path->active; blk++, level++) { if (blk->bp) { blk->disk_blkno = XFS_BUF_ADDR(blk->bp); blk->bp = NULL; } else { blk->disk_blkno = 0; } } return 0; } /* * Reattach the buffers to the state structure based on the disk block * numbers stored in the state structure. * This is done after some set of transaction commits have released those * buffers from our grip. */ STATIC int xfs_attr_refillstate(xfs_da_state_t *state) { xfs_da_state_path_t *path; xfs_da_state_blk_t *blk; int level, error; trace_xfs_attr_refillstate(state->args); /* * Roll down the "path" in the state structure, storing the on-disk * block number for those buffers in the "path". */ path = &state->path; ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH)); for (blk = path->blk, level = 0; level < path->active; blk++, level++) { if (blk->disk_blkno) { error = xfs_da3_node_read(state->args->trans, state->args->dp, blk->blkno, blk->disk_blkno, &blk->bp, XFS_ATTR_FORK); if (error) return error; } else { blk->bp = NULL; } } /* * Roll down the "altpath" in the state structure, storing the on-disk * block number for those buffers in the "altpath". */ path = &state->altpath; ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH)); for (blk = path->blk, level = 0; level < path->active; blk++, level++) { if (blk->disk_blkno) { error = xfs_da3_node_read(state->args->trans, state->args->dp, blk->blkno, blk->disk_blkno, &blk->bp, XFS_ATTR_FORK); if (error) return error; } else { blk->bp = NULL; } } return 0; } /* * Look up a filename in a node attribute list. * * This routine gets called for any attribute fork that has more than one * block, ie: both true Btree attr lists and for single-leaf-blocks with * "remote" values taking up more blocks. */ STATIC int xfs_attr_node_get(xfs_da_args_t *args) { xfs_da_state_t *state; xfs_da_state_blk_t *blk; int error, retval; int i; trace_xfs_attr_node_get(args); state = xfs_da_state_alloc(); state->args = args; state->mp = args->dp->i_mount; /* * Search to see if name exists, and get back a pointer to it. */ error = xfs_da3_node_lookup_int(state, &retval); if (error) { retval = error; } else if (retval == -EEXIST) { blk = &state->path.blk[ state->path.active-1 ]; ASSERT(blk->bp != NULL); ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC); /* * Get the value, local or "remote" */ retval = xfs_attr3_leaf_getvalue(blk->bp, args); if (!retval && (args->rmtblkno > 0) && !(args->flags & ATTR_KERNOVAL)) { retval = xfs_attr_rmtval_get(args); } } /* * If not in a transaction, we have to release all the buffers. */ for (i = 0; i < state->path.active; i++) { xfs_trans_brelse(args->trans, state->path.blk[i].bp); state->path.blk[i].bp = NULL; } xfs_da_state_free(state); return retval; } partclone-0.2.86/src/xfs/xfs_attr_leaf.c000066400000000000000000002351651262102574200201670ustar00rootroot00000000000000/* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * Copyright (c) 2013 Red Hat, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_bit.h" #include "xfs_sb.h" #include "xfs_mount.h" #include "xfs_da_format.h" #include "xfs_da_btree.h" #include "xfs_inode.h" #include "xfs_trans.h" #include "xfs_bmap_btree.h" #include "xfs_bmap.h" #include "xfs_attr_sf.h" #include "xfs_attr_remote.h" #include "xfs_attr_leaf.h" #include "xfs_trace.h" #include "xfs_cksum.h" #include "xfs_dir2.h" /* * xfs_attr_leaf.c * * Routines to implement leaf blocks of attributes as Btrees of hashed names. */ /*======================================================================== * Function prototypes for the kernel. *========================================================================*/ /* * Routines used for growing the Btree. */ STATIC int xfs_attr3_leaf_create(struct xfs_da_args *args, xfs_dablk_t which_block, struct xfs_buf **bpp); STATIC int xfs_attr3_leaf_add_work(struct xfs_buf *leaf_buffer, struct xfs_attr3_icleaf_hdr *ichdr, struct xfs_da_args *args, int freemap_index); STATIC void xfs_attr3_leaf_compact(struct xfs_da_args *args, struct xfs_attr3_icleaf_hdr *ichdr, struct xfs_buf *leaf_buffer); STATIC void xfs_attr3_leaf_rebalance(xfs_da_state_t *state, xfs_da_state_blk_t *blk1, xfs_da_state_blk_t *blk2); STATIC int xfs_attr3_leaf_figure_balance(xfs_da_state_t *state, xfs_da_state_blk_t *leaf_blk_1, struct xfs_attr3_icleaf_hdr *ichdr1, xfs_da_state_blk_t *leaf_blk_2, struct xfs_attr3_icleaf_hdr *ichdr2, int *number_entries_in_blk1, int *number_usedbytes_in_blk1); /* * Utility routines. */ STATIC void xfs_attr3_leaf_moveents(struct xfs_da_args *args, struct xfs_attr_leafblock *src_leaf, struct xfs_attr3_icleaf_hdr *src_ichdr, int src_start, struct xfs_attr_leafblock *dst_leaf, struct xfs_attr3_icleaf_hdr *dst_ichdr, int dst_start, int move_count); STATIC int xfs_attr_leaf_entsize(xfs_attr_leafblock_t *leaf, int index); /* * attr3 block 'firstused' conversion helpers. * * firstused refers to the offset of the first used byte of the nameval region * of an attr leaf block. The region starts at the tail of the block and expands * backwards towards the middle. As such, firstused is initialized to the block * size for an empty leaf block and is reduced from there. * * The attr3 block size is pegged to the fsb size and the maximum fsb is 64k. * The in-core firstused field is 32-bit and thus supports the maximum fsb size. * The on-disk field is only 16-bit, however, and overflows at 64k. Since this * only occurs at exactly 64k, we use zero as a magic on-disk value to represent * the attr block size. The following helpers manage the conversion between the * in-core and on-disk formats. */ static void xfs_attr3_leaf_firstused_from_disk( struct xfs_da_geometry *geo, struct xfs_attr3_icleaf_hdr *to, struct xfs_attr_leafblock *from) { struct xfs_attr3_leaf_hdr *hdr3; if (from->hdr.info.magic == cpu_to_be16(XFS_ATTR3_LEAF_MAGIC)) { hdr3 = (struct xfs_attr3_leaf_hdr *) from; to->firstused = be16_to_cpu(hdr3->firstused); } else { to->firstused = be16_to_cpu(from->hdr.firstused); } /* * Convert from the magic fsb size value to actual blocksize. This * should only occur for empty blocks when the block size overflows * 16-bits. */ if (to->firstused == XFS_ATTR3_LEAF_NULLOFF) { ASSERT(!to->count && !to->usedbytes); ASSERT(geo->blksize > USHRT_MAX); to->firstused = geo->blksize; } } static void xfs_attr3_leaf_firstused_to_disk( struct xfs_da_geometry *geo, struct xfs_attr_leafblock *to, struct xfs_attr3_icleaf_hdr *from) { struct xfs_attr3_leaf_hdr *hdr3; uint32_t firstused; /* magic value should only be seen on disk */ ASSERT(from->firstused != XFS_ATTR3_LEAF_NULLOFF); /* * Scale down the 32-bit in-core firstused value to the 16-bit on-disk * value. This only overflows at the max supported value of 64k. Use the * magic on-disk value to represent block size in this case. */ firstused = from->firstused; if (firstused > USHRT_MAX) { ASSERT(from->firstused == geo->blksize); firstused = XFS_ATTR3_LEAF_NULLOFF; } if (from->magic == XFS_ATTR3_LEAF_MAGIC) { hdr3 = (struct xfs_attr3_leaf_hdr *) to; hdr3->firstused = cpu_to_be16(firstused); } else { to->hdr.firstused = cpu_to_be16(firstused); } } void xfs_attr3_leaf_hdr_from_disk( struct xfs_da_geometry *geo, struct xfs_attr3_icleaf_hdr *to, struct xfs_attr_leafblock *from) { int i; ASSERT(from->hdr.info.magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC) || from->hdr.info.magic == cpu_to_be16(XFS_ATTR3_LEAF_MAGIC)); if (from->hdr.info.magic == cpu_to_be16(XFS_ATTR3_LEAF_MAGIC)) { struct xfs_attr3_leaf_hdr *hdr3 = (struct xfs_attr3_leaf_hdr *)from; to->forw = be32_to_cpu(hdr3->info.hdr.forw); to->back = be32_to_cpu(hdr3->info.hdr.back); to->magic = be16_to_cpu(hdr3->info.hdr.magic); to->count = be16_to_cpu(hdr3->count); to->usedbytes = be16_to_cpu(hdr3->usedbytes); xfs_attr3_leaf_firstused_from_disk(geo, to, from); to->holes = hdr3->holes; for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; i++) { to->freemap[i].base = be16_to_cpu(hdr3->freemap[i].base); to->freemap[i].size = be16_to_cpu(hdr3->freemap[i].size); } return; } to->forw = be32_to_cpu(from->hdr.info.forw); to->back = be32_to_cpu(from->hdr.info.back); to->magic = be16_to_cpu(from->hdr.info.magic); to->count = be16_to_cpu(from->hdr.count); to->usedbytes = be16_to_cpu(from->hdr.usedbytes); xfs_attr3_leaf_firstused_from_disk(geo, to, from); to->holes = from->hdr.holes; for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; i++) { to->freemap[i].base = be16_to_cpu(from->hdr.freemap[i].base); to->freemap[i].size = be16_to_cpu(from->hdr.freemap[i].size); } } void xfs_attr3_leaf_hdr_to_disk( struct xfs_da_geometry *geo, struct xfs_attr_leafblock *to, struct xfs_attr3_icleaf_hdr *from) { int i; ASSERT(from->magic == XFS_ATTR_LEAF_MAGIC || from->magic == XFS_ATTR3_LEAF_MAGIC); if (from->magic == XFS_ATTR3_LEAF_MAGIC) { struct xfs_attr3_leaf_hdr *hdr3 = (struct xfs_attr3_leaf_hdr *)to; hdr3->info.hdr.forw = cpu_to_be32(from->forw); hdr3->info.hdr.back = cpu_to_be32(from->back); hdr3->info.hdr.magic = cpu_to_be16(from->magic); hdr3->count = cpu_to_be16(from->count); hdr3->usedbytes = cpu_to_be16(from->usedbytes); xfs_attr3_leaf_firstused_to_disk(geo, to, from); hdr3->holes = from->holes; hdr3->pad1 = 0; for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; i++) { hdr3->freemap[i].base = cpu_to_be16(from->freemap[i].base); hdr3->freemap[i].size = cpu_to_be16(from->freemap[i].size); } return; } to->hdr.info.forw = cpu_to_be32(from->forw); to->hdr.info.back = cpu_to_be32(from->back); to->hdr.info.magic = cpu_to_be16(from->magic); to->hdr.count = cpu_to_be16(from->count); to->hdr.usedbytes = cpu_to_be16(from->usedbytes); xfs_attr3_leaf_firstused_to_disk(geo, to, from); to->hdr.holes = from->holes; to->hdr.pad1 = 0; for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; i++) { to->hdr.freemap[i].base = cpu_to_be16(from->freemap[i].base); to->hdr.freemap[i].size = cpu_to_be16(from->freemap[i].size); } } static bool xfs_attr3_leaf_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_target->bt_mount; struct xfs_attr_leafblock *leaf = bp->b_addr; struct xfs_attr3_icleaf_hdr ichdr; xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &ichdr, leaf); if (xfs_sb_version_hascrc(&mp->m_sb)) { struct xfs_da3_node_hdr *hdr3 = bp->b_addr; if (ichdr.magic != XFS_ATTR3_LEAF_MAGIC) return false; if (!uuid_equal(&hdr3->info.uuid, &mp->m_sb.sb_meta_uuid)) return false; if (be64_to_cpu(hdr3->info.blkno) != bp->b_bn) return false; } else { if (ichdr.magic != XFS_ATTR_LEAF_MAGIC) return false; } if (ichdr.count == 0) return false; /* XXX: need to range check rest of attr header values */ /* XXX: hash order check? */ return true; } static void xfs_attr3_leaf_write_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_target->bt_mount; struct xfs_buf_log_item *bip = bp->b_fspriv; struct xfs_attr3_leaf_hdr *hdr3 = bp->b_addr; if (!xfs_attr3_leaf_verify(bp)) { xfs_buf_ioerror(bp, -EFSCORRUPTED); xfs_verifier_error(bp); return; } if (!xfs_sb_version_hascrc(&mp->m_sb)) return; if (bip) hdr3->info.lsn = cpu_to_be64(bip->bli_item.li_lsn); xfs_buf_update_cksum(bp, XFS_ATTR3_LEAF_CRC_OFF); } /* * leaf/node format detection on trees is sketchy, so a node read can be done on * leaf level blocks when detection identifies the tree as a node format tree * incorrectly. In this case, we need to swap the verifier to match the correct * format of the block being read. */ static void xfs_attr3_leaf_read_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_target->bt_mount; if (xfs_sb_version_hascrc(&mp->m_sb) && !xfs_buf_verify_cksum(bp, XFS_ATTR3_LEAF_CRC_OFF)) xfs_buf_ioerror(bp, -EFSBADCRC); else if (!xfs_attr3_leaf_verify(bp)) xfs_buf_ioerror(bp, -EFSCORRUPTED); if (bp->b_error) xfs_verifier_error(bp); } const struct xfs_buf_ops xfs_attr3_leaf_buf_ops = { .verify_read = xfs_attr3_leaf_read_verify, .verify_write = xfs_attr3_leaf_write_verify, }; int xfs_attr3_leaf_read( struct xfs_trans *tp, struct xfs_inode *dp, xfs_dablk_t bno, xfs_daddr_t mappedbno, struct xfs_buf **bpp) { int err; err = xfs_da_read_buf(tp, dp, bno, mappedbno, bpp, XFS_ATTR_FORK, &xfs_attr3_leaf_buf_ops); if (!err && tp) xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_ATTR_LEAF_BUF); return err; } /*======================================================================== * Namespace helper routines *========================================================================*/ /* * If namespace bits don't match return 0. * If all match then return 1. */ STATIC int xfs_attr_namesp_match(int arg_flags, int ondisk_flags) { return XFS_ATTR_NSP_ONDISK(ondisk_flags) == XFS_ATTR_NSP_ARGS_TO_ONDISK(arg_flags); } /*======================================================================== * External routines when attribute fork size < XFS_LITINO(mp). *========================================================================*/ /* * Query whether the requested number of additional bytes of extended * attribute space will be able to fit inline. * * Returns zero if not, else the di_forkoff fork offset to be used in the * literal area for attribute data once the new bytes have been added. * * di_forkoff must be 8 byte aligned, hence is stored as a >>3 value; * special case for dev/uuid inodes, they have fixed size data forks. */ int xfs_attr_shortform_bytesfit(xfs_inode_t *dp, int bytes) { int offset; int minforkoff; /* lower limit on valid forkoff locations */ int maxforkoff; /* upper limit on valid forkoff locations */ int dsize; xfs_mount_t *mp = dp->i_mount; /* rounded down */ offset = (XFS_LITINO(mp, dp->i_d.di_version) - bytes) >> 3; switch (dp->i_d.di_format) { case XFS_DINODE_FMT_DEV: minforkoff = roundup(sizeof(xfs_dev_t), 8) >> 3; return (offset >= minforkoff) ? minforkoff : 0; case XFS_DINODE_FMT_UUID: minforkoff = roundup(sizeof(uuid_t), 8) >> 3; return (offset >= minforkoff) ? minforkoff : 0; } /* * If the requested numbers of bytes is smaller or equal to the * current attribute fork size we can always proceed. * * Note that if_bytes in the data fork might actually be larger than * the current data fork size is due to delalloc extents. In that * case either the extent count will go down when they are converted * to real extents, or the delalloc conversion will take care of the * literal area rebalancing. */ if (bytes <= XFS_IFORK_ASIZE(dp)) return dp->i_d.di_forkoff; /* * For attr2 we can try to move the forkoff if there is space in the * literal area, but for the old format we are done if there is no * space in the fixed attribute fork. */ if (!(mp->m_flags & XFS_MOUNT_ATTR2)) return 0; dsize = dp->i_df.if_bytes; switch (dp->i_d.di_format) { case XFS_DINODE_FMT_EXTENTS: /* * If there is no attr fork and the data fork is extents, * determine if creating the default attr fork will result * in the extents form migrating to btree. If so, the * minimum offset only needs to be the space required for * the btree root. */ if (!dp->i_d.di_forkoff && dp->i_df.if_bytes > xfs_default_attroffset(dp)) dsize = XFS_BMDR_SPACE_CALC(MINDBTPTRS); break; case XFS_DINODE_FMT_BTREE: /* * If we have a data btree then keep forkoff if we have one, * otherwise we are adding a new attr, so then we set * minforkoff to where the btree root can finish so we have * plenty of room for attrs */ if (dp->i_d.di_forkoff) { if (offset < dp->i_d.di_forkoff) return 0; return dp->i_d.di_forkoff; } dsize = XFS_BMAP_BROOT_SPACE(mp, dp->i_df.if_broot); break; } /* * A data fork btree root must have space for at least * MINDBTPTRS key/ptr pairs if the data fork is small or empty. */ minforkoff = MAX(dsize, XFS_BMDR_SPACE_CALC(MINDBTPTRS)); minforkoff = roundup(minforkoff, 8) >> 3; /* attr fork btree root can have at least this many key/ptr pairs */ maxforkoff = XFS_LITINO(mp, dp->i_d.di_version) - XFS_BMDR_SPACE_CALC(MINABTPTRS); maxforkoff = maxforkoff >> 3; /* rounded down */ if (offset >= maxforkoff) return maxforkoff; if (offset >= minforkoff) return offset; return 0; } /* * Switch on the ATTR2 superblock bit (implies also FEATURES2) */ STATIC void xfs_sbversion_add_attr2(xfs_mount_t *mp, xfs_trans_t *tp) { if ((mp->m_flags & XFS_MOUNT_ATTR2) && !(xfs_sb_version_hasattr2(&mp->m_sb))) { spin_lock(&mp->m_sb_lock); if (!xfs_sb_version_hasattr2(&mp->m_sb)) { xfs_sb_version_addattr2(&mp->m_sb); spin_unlock(&mp->m_sb_lock); xfs_log_sb(tp); } else spin_unlock(&mp->m_sb_lock); } } /* * Create the initial contents of a shortform attribute list. */ void xfs_attr_shortform_create(xfs_da_args_t *args) { xfs_attr_sf_hdr_t *hdr; xfs_inode_t *dp; xfs_ifork_t *ifp; trace_xfs_attr_sf_create(args); dp = args->dp; ASSERT(dp != NULL); ifp = dp->i_afp; ASSERT(ifp != NULL); ASSERT(ifp->if_bytes == 0); if (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS) { ifp->if_flags &= ~XFS_IFEXTENTS; /* just in case */ dp->i_d.di_aformat = XFS_DINODE_FMT_LOCAL; ifp->if_flags |= XFS_IFINLINE; } else { ASSERT(ifp->if_flags & XFS_IFINLINE); } xfs_idata_realloc(dp, sizeof(*hdr), XFS_ATTR_FORK); hdr = (xfs_attr_sf_hdr_t *)ifp->if_u1.if_data; hdr->count = 0; hdr->totsize = cpu_to_be16(sizeof(*hdr)); xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_ADATA); } /* * Add a name/value pair to the shortform attribute list. * Overflow from the inode has already been checked for. */ void xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff) { xfs_attr_shortform_t *sf; xfs_attr_sf_entry_t *sfe; int i, offset, size; xfs_mount_t *mp; xfs_inode_t *dp; xfs_ifork_t *ifp; trace_xfs_attr_sf_add(args); dp = args->dp; mp = dp->i_mount; dp->i_d.di_forkoff = forkoff; ifp = dp->i_afp; ASSERT(ifp->if_flags & XFS_IFINLINE); sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data; sfe = &sf->list[0]; for (i = 0; i < sf->hdr.count; sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) { #ifdef DEBUG if (sfe->namelen != args->namelen) continue; if (memcmp(args->name, sfe->nameval, args->namelen) != 0) continue; if (!xfs_attr_namesp_match(args->flags, sfe->flags)) continue; ASSERT(0); #endif } offset = (char *)sfe - (char *)sf; size = XFS_ATTR_SF_ENTSIZE_BYNAME(args->namelen, args->valuelen); xfs_idata_realloc(dp, size, XFS_ATTR_FORK); sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data; sfe = (xfs_attr_sf_entry_t *)((char *)sf + offset); sfe->namelen = args->namelen; sfe->valuelen = args->valuelen; sfe->flags = XFS_ATTR_NSP_ARGS_TO_ONDISK(args->flags); memcpy(sfe->nameval, args->name, args->namelen); memcpy(&sfe->nameval[args->namelen], args->value, args->valuelen); sf->hdr.count++; be16_add_cpu(&sf->hdr.totsize, size); xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_ADATA); xfs_sbversion_add_attr2(mp, args->trans); } /* * After the last attribute is removed revert to original inode format, * making all literal area available to the data fork once more. */ void xfs_attr_fork_remove( struct xfs_inode *ip, struct xfs_trans *tp) { xfs_idestroy_fork(ip, XFS_ATTR_FORK); ip->i_d.di_forkoff = 0; ip->i_d.di_aformat = XFS_DINODE_FMT_EXTENTS; ASSERT(ip->i_d.di_anextents == 0); ASSERT(ip->i_afp == NULL); xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); } /* * Remove an attribute from the shortform attribute list structure. */ int xfs_attr_shortform_remove(xfs_da_args_t *args) { xfs_attr_shortform_t *sf; xfs_attr_sf_entry_t *sfe; int base, size=0, end, totsize, i; xfs_mount_t *mp; xfs_inode_t *dp; trace_xfs_attr_sf_remove(args); dp = args->dp; mp = dp->i_mount; base = sizeof(xfs_attr_sf_hdr_t); sf = (xfs_attr_shortform_t *)dp->i_afp->if_u1.if_data; sfe = &sf->list[0]; end = sf->hdr.count; for (i = 0; i < end; sfe = XFS_ATTR_SF_NEXTENTRY(sfe), base += size, i++) { size = XFS_ATTR_SF_ENTSIZE(sfe); if (sfe->namelen != args->namelen) continue; if (memcmp(sfe->nameval, args->name, args->namelen) != 0) continue; if (!xfs_attr_namesp_match(args->flags, sfe->flags)) continue; break; } if (i == end) return -ENOATTR; /* * Fix up the attribute fork data, covering the hole */ end = base + size; totsize = be16_to_cpu(sf->hdr.totsize); if (end != totsize) memmove(&((char *)sf)[base], &((char *)sf)[end], totsize - end); sf->hdr.count--; be16_add_cpu(&sf->hdr.totsize, -size); /* * Fix up the start offset of the attribute fork */ totsize -= size; if (totsize == sizeof(xfs_attr_sf_hdr_t) && (mp->m_flags & XFS_MOUNT_ATTR2) && (dp->i_d.di_format != XFS_DINODE_FMT_BTREE) && !(args->op_flags & XFS_DA_OP_ADDNAME)) { xfs_attr_fork_remove(dp, args->trans); } else { xfs_idata_realloc(dp, -size, XFS_ATTR_FORK); dp->i_d.di_forkoff = xfs_attr_shortform_bytesfit(dp, totsize); ASSERT(dp->i_d.di_forkoff); ASSERT(totsize > sizeof(xfs_attr_sf_hdr_t) || (args->op_flags & XFS_DA_OP_ADDNAME) || !(mp->m_flags & XFS_MOUNT_ATTR2) || dp->i_d.di_format == XFS_DINODE_FMT_BTREE); xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_ADATA); } xfs_sbversion_add_attr2(mp, args->trans); return 0; } /* * Look up a name in a shortform attribute list structure. */ /*ARGSUSED*/ int xfs_attr_shortform_lookup(xfs_da_args_t *args) { xfs_attr_shortform_t *sf; xfs_attr_sf_entry_t *sfe; int i; xfs_ifork_t *ifp; trace_xfs_attr_sf_lookup(args); ifp = args->dp->i_afp; ASSERT(ifp->if_flags & XFS_IFINLINE); sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data; sfe = &sf->list[0]; for (i = 0; i < sf->hdr.count; sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) { if (sfe->namelen != args->namelen) continue; if (memcmp(args->name, sfe->nameval, args->namelen) != 0) continue; if (!xfs_attr_namesp_match(args->flags, sfe->flags)) continue; return -EEXIST; } return -ENOATTR; } /* * Look up a name in a shortform attribute list structure. */ /*ARGSUSED*/ int xfs_attr_shortform_getvalue(xfs_da_args_t *args) { xfs_attr_shortform_t *sf; xfs_attr_sf_entry_t *sfe; int i; ASSERT(args->dp->i_afp->if_flags == XFS_IFINLINE); sf = (xfs_attr_shortform_t *)args->dp->i_afp->if_u1.if_data; sfe = &sf->list[0]; for (i = 0; i < sf->hdr.count; sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) { if (sfe->namelen != args->namelen) continue; if (memcmp(args->name, sfe->nameval, args->namelen) != 0) continue; if (!xfs_attr_namesp_match(args->flags, sfe->flags)) continue; if (args->flags & ATTR_KERNOVAL) { args->valuelen = sfe->valuelen; return -EEXIST; } if (args->valuelen < sfe->valuelen) { args->valuelen = sfe->valuelen; return -ERANGE; } args->valuelen = sfe->valuelen; memcpy(args->value, &sfe->nameval[args->namelen], args->valuelen); return -EEXIST; } return -ENOATTR; } /* * Convert from using the shortform to the leaf. */ int xfs_attr_shortform_to_leaf(xfs_da_args_t *args) { xfs_inode_t *dp; xfs_attr_shortform_t *sf; xfs_attr_sf_entry_t *sfe; xfs_da_args_t nargs; char *tmpbuffer; int error, i, size; xfs_dablk_t blkno; struct xfs_buf *bp; xfs_ifork_t *ifp; trace_xfs_attr_sf_to_leaf(args); dp = args->dp; ifp = dp->i_afp; sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data; size = be16_to_cpu(sf->hdr.totsize); tmpbuffer = kmem_alloc(size, KM_SLEEP); ASSERT(tmpbuffer != NULL); memcpy(tmpbuffer, ifp->if_u1.if_data, size); sf = (xfs_attr_shortform_t *)tmpbuffer; xfs_idata_realloc(dp, -size, XFS_ATTR_FORK); xfs_bmap_local_to_extents_empty(dp, XFS_ATTR_FORK); bp = NULL; error = xfs_da_grow_inode(args, &blkno); if (error) { /* * If we hit an IO error middle of the transaction inside * grow_inode(), we may have inconsistent data. Bail out. */ if (error == -EIO) goto out; xfs_idata_realloc(dp, size, XFS_ATTR_FORK); /* try to put */ memcpy(ifp->if_u1.if_data, tmpbuffer, size); /* it back */ goto out; } ASSERT(blkno == 0); error = xfs_attr3_leaf_create(args, blkno, &bp); if (error) { error = xfs_da_shrink_inode(args, 0, bp); bp = NULL; if (error) goto out; xfs_idata_realloc(dp, size, XFS_ATTR_FORK); /* try to put */ memcpy(ifp->if_u1.if_data, tmpbuffer, size); /* it back */ goto out; } memset((char *)&nargs, 0, sizeof(nargs)); nargs.dp = dp; nargs.geo = args->geo; nargs.firstblock = args->firstblock; nargs.flist = args->flist; nargs.total = args->total; nargs.whichfork = XFS_ATTR_FORK; nargs.trans = args->trans; nargs.op_flags = XFS_DA_OP_OKNOENT; sfe = &sf->list[0]; for (i = 0; i < sf->hdr.count; i++) { nargs.name = sfe->nameval; nargs.namelen = sfe->namelen; nargs.value = &sfe->nameval[nargs.namelen]; nargs.valuelen = sfe->valuelen; nargs.hashval = xfs_da_hashname(sfe->nameval, sfe->namelen); nargs.flags = XFS_ATTR_NSP_ONDISK_TO_ARGS(sfe->flags); error = xfs_attr3_leaf_lookup_int(bp, &nargs); /* set a->index */ ASSERT(error == -ENOATTR); error = xfs_attr3_leaf_add(bp, &nargs); ASSERT(error != -ENOSPC); if (error) goto out; sfe = XFS_ATTR_SF_NEXTENTRY(sfe); } error = 0; out: kmem_free(tmpbuffer); return error; } /* * Check a leaf attribute block to see if all the entries would fit into * a shortform attribute list. */ int xfs_attr_shortform_allfit( struct xfs_buf *bp, struct xfs_inode *dp) { struct xfs_attr_leafblock *leaf; struct xfs_attr_leaf_entry *entry; xfs_attr_leaf_name_local_t *name_loc; struct xfs_attr3_icleaf_hdr leafhdr; int bytes; int i; struct xfs_mount *mp = bp->b_target->bt_mount; leaf = bp->b_addr; xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &leafhdr, leaf); entry = xfs_attr3_leaf_entryp(leaf); bytes = sizeof(struct xfs_attr_sf_hdr); for (i = 0; i < leafhdr.count; entry++, i++) { if (entry->flags & XFS_ATTR_INCOMPLETE) continue; /* don't copy partial entries */ if (!(entry->flags & XFS_ATTR_LOCAL)) return 0; name_loc = xfs_attr3_leaf_name_local(leaf, i); if (name_loc->namelen >= XFS_ATTR_SF_ENTSIZE_MAX) return 0; if (be16_to_cpu(name_loc->valuelen) >= XFS_ATTR_SF_ENTSIZE_MAX) return 0; bytes += sizeof(struct xfs_attr_sf_entry) - 1 + name_loc->namelen + be16_to_cpu(name_loc->valuelen); } if ((dp->i_mount->m_flags & XFS_MOUNT_ATTR2) && (dp->i_d.di_format != XFS_DINODE_FMT_BTREE) && (bytes == sizeof(struct xfs_attr_sf_hdr))) return -1; return xfs_attr_shortform_bytesfit(dp, bytes); } /* * Convert a leaf attribute list to shortform attribute list */ int xfs_attr3_leaf_to_shortform( struct xfs_buf *bp, struct xfs_da_args *args, int forkoff) { struct xfs_attr_leafblock *leaf; struct xfs_attr3_icleaf_hdr ichdr; struct xfs_attr_leaf_entry *entry; struct xfs_attr_leaf_name_local *name_loc; struct xfs_da_args nargs; struct xfs_inode *dp = args->dp; char *tmpbuffer; int error; int i; trace_xfs_attr_leaf_to_sf(args); tmpbuffer = kmem_alloc(args->geo->blksize, KM_SLEEP); if (!tmpbuffer) return -ENOMEM; memcpy(tmpbuffer, bp->b_addr, args->geo->blksize); leaf = (xfs_attr_leafblock_t *)tmpbuffer; xfs_attr3_leaf_hdr_from_disk(args->geo, &ichdr, leaf); entry = xfs_attr3_leaf_entryp(leaf); /* XXX (dgc): buffer is about to be marked stale - why zero it? */ memset(bp->b_addr, 0, args->geo->blksize); /* * Clean out the prior contents of the attribute list. */ error = xfs_da_shrink_inode(args, 0, bp); if (error) goto out; if (forkoff == -1) { ASSERT(dp->i_mount->m_flags & XFS_MOUNT_ATTR2); ASSERT(dp->i_d.di_format != XFS_DINODE_FMT_BTREE); xfs_attr_fork_remove(dp, args->trans); goto out; } xfs_attr_shortform_create(args); /* * Copy the attributes */ memset((char *)&nargs, 0, sizeof(nargs)); nargs.geo = args->geo; nargs.dp = dp; nargs.firstblock = args->firstblock; nargs.flist = args->flist; nargs.total = args->total; nargs.whichfork = XFS_ATTR_FORK; nargs.trans = args->trans; nargs.op_flags = XFS_DA_OP_OKNOENT; for (i = 0; i < ichdr.count; entry++, i++) { if (entry->flags & XFS_ATTR_INCOMPLETE) continue; /* don't copy partial entries */ if (!entry->nameidx) continue; ASSERT(entry->flags & XFS_ATTR_LOCAL); name_loc = xfs_attr3_leaf_name_local(leaf, i); nargs.name = name_loc->nameval; nargs.namelen = name_loc->namelen; nargs.value = &name_loc->nameval[nargs.namelen]; nargs.valuelen = be16_to_cpu(name_loc->valuelen); nargs.hashval = be32_to_cpu(entry->hashval); nargs.flags = XFS_ATTR_NSP_ONDISK_TO_ARGS(entry->flags); xfs_attr_shortform_add(&nargs, forkoff); } error = 0; out: kmem_free(tmpbuffer); return error; } /* * Convert from using a single leaf to a root node and a leaf. */ int xfs_attr3_leaf_to_node( struct xfs_da_args *args) { struct xfs_attr_leafblock *leaf; struct xfs_attr3_icleaf_hdr icleafhdr; struct xfs_attr_leaf_entry *entries; struct xfs_da_node_entry *btree; struct xfs_da3_icnode_hdr icnodehdr; struct xfs_da_intnode *node; struct xfs_inode *dp = args->dp; struct xfs_mount *mp = dp->i_mount; struct xfs_buf *bp1 = NULL; struct xfs_buf *bp2 = NULL; xfs_dablk_t blkno; int error; trace_xfs_attr_leaf_to_node(args); error = xfs_da_grow_inode(args, &blkno); if (error) goto out; error = xfs_attr3_leaf_read(args->trans, dp, 0, -1, &bp1); if (error) goto out; error = xfs_da_get_buf(args->trans, dp, blkno, -1, &bp2, XFS_ATTR_FORK); if (error) goto out; /* copy leaf to new buffer, update identifiers */ xfs_trans_buf_set_type(args->trans, bp2, XFS_BLFT_ATTR_LEAF_BUF); bp2->b_ops = bp1->b_ops; memcpy(bp2->b_addr, bp1->b_addr, args->geo->blksize); if (xfs_sb_version_hascrc(&mp->m_sb)) { struct xfs_da3_blkinfo *hdr3 = bp2->b_addr; hdr3->blkno = cpu_to_be64(bp2->b_bn); } xfs_trans_log_buf(args->trans, bp2, 0, args->geo->blksize - 1); /* * Set up the new root node. */ error = xfs_da3_node_create(args, 0, 1, &bp1, XFS_ATTR_FORK); if (error) goto out; node = bp1->b_addr; dp->d_ops->node_hdr_from_disk(&icnodehdr, node); btree = dp->d_ops->node_tree_p(node); leaf = bp2->b_addr; xfs_attr3_leaf_hdr_from_disk(args->geo, &icleafhdr, leaf); entries = xfs_attr3_leaf_entryp(leaf); /* both on-disk, don't endian-flip twice */ btree[0].hashval = entries[icleafhdr.count - 1].hashval; btree[0].before = cpu_to_be32(blkno); icnodehdr.count = 1; dp->d_ops->node_hdr_to_disk(node, &icnodehdr); xfs_trans_log_buf(args->trans, bp1, 0, args->geo->blksize - 1); error = 0; out: return error; } /*======================================================================== * Routines used for growing the Btree. *========================================================================*/ /* * Create the initial contents of a leaf attribute list * or a leaf in a node attribute list. */ STATIC int xfs_attr3_leaf_create( struct xfs_da_args *args, xfs_dablk_t blkno, struct xfs_buf **bpp) { struct xfs_attr_leafblock *leaf; struct xfs_attr3_icleaf_hdr ichdr; struct xfs_inode *dp = args->dp; struct xfs_mount *mp = dp->i_mount; struct xfs_buf *bp; int error; trace_xfs_attr_leaf_create(args); error = xfs_da_get_buf(args->trans, args->dp, blkno, -1, &bp, XFS_ATTR_FORK); if (error) return error; bp->b_ops = &xfs_attr3_leaf_buf_ops; xfs_trans_buf_set_type(args->trans, bp, XFS_BLFT_ATTR_LEAF_BUF); leaf = bp->b_addr; memset(leaf, 0, args->geo->blksize); memset(&ichdr, 0, sizeof(ichdr)); ichdr.firstused = args->geo->blksize; if (xfs_sb_version_hascrc(&mp->m_sb)) { struct xfs_da3_blkinfo *hdr3 = bp->b_addr; ichdr.magic = XFS_ATTR3_LEAF_MAGIC; hdr3->blkno = cpu_to_be64(bp->b_bn); hdr3->owner = cpu_to_be64(dp->i_ino); uuid_copy(&hdr3->uuid, &mp->m_sb.sb_meta_uuid); ichdr.freemap[0].base = sizeof(struct xfs_attr3_leaf_hdr); } else { ichdr.magic = XFS_ATTR_LEAF_MAGIC; ichdr.freemap[0].base = sizeof(struct xfs_attr_leaf_hdr); } ichdr.freemap[0].size = ichdr.firstused - ichdr.freemap[0].base; xfs_attr3_leaf_hdr_to_disk(args->geo, leaf, &ichdr); xfs_trans_log_buf(args->trans, bp, 0, args->geo->blksize - 1); *bpp = bp; return 0; } /* * Split the leaf node, rebalance, then add the new entry. */ int xfs_attr3_leaf_split( struct xfs_da_state *state, struct xfs_da_state_blk *oldblk, struct xfs_da_state_blk *newblk) { xfs_dablk_t blkno; int error; trace_xfs_attr_leaf_split(state->args); /* * Allocate space for a new leaf node. */ ASSERT(oldblk->magic == XFS_ATTR_LEAF_MAGIC); error = xfs_da_grow_inode(state->args, &blkno); if (error) return error; error = xfs_attr3_leaf_create(state->args, blkno, &newblk->bp); if (error) return error; newblk->blkno = blkno; newblk->magic = XFS_ATTR_LEAF_MAGIC; /* * Rebalance the entries across the two leaves. * NOTE: rebalance() currently depends on the 2nd block being empty. */ xfs_attr3_leaf_rebalance(state, oldblk, newblk); error = xfs_da3_blk_link(state, oldblk, newblk); if (error) return error; /* * Save info on "old" attribute for "atomic rename" ops, leaf_add() * modifies the index/blkno/rmtblk/rmtblkcnt fields to show the * "new" attrs info. Will need the "old" info to remove it later. * * Insert the "new" entry in the correct block. */ if (state->inleaf) { trace_xfs_attr_leaf_add_old(state->args); error = xfs_attr3_leaf_add(oldblk->bp, state->args); } else { trace_xfs_attr_leaf_add_new(state->args); error = xfs_attr3_leaf_add(newblk->bp, state->args); } /* * Update last hashval in each block since we added the name. */ oldblk->hashval = xfs_attr_leaf_lasthash(oldblk->bp, NULL); newblk->hashval = xfs_attr_leaf_lasthash(newblk->bp, NULL); return error; } /* * Add a name to the leaf attribute list structure. */ int xfs_attr3_leaf_add( struct xfs_buf *bp, struct xfs_da_args *args) { struct xfs_attr_leafblock *leaf; struct xfs_attr3_icleaf_hdr ichdr; int tablesize; int entsize; int sum; int tmp; int i; trace_xfs_attr_leaf_add(args); leaf = bp->b_addr; xfs_attr3_leaf_hdr_from_disk(args->geo, &ichdr, leaf); ASSERT(args->index >= 0 && args->index <= ichdr.count); entsize = xfs_attr_leaf_newentsize(args, NULL); /* * Search through freemap for first-fit on new name length. * (may need to figure in size of entry struct too) */ tablesize = (ichdr.count + 1) * sizeof(xfs_attr_leaf_entry_t) + xfs_attr3_leaf_hdr_size(leaf); for (sum = 0, i = XFS_ATTR_LEAF_MAPSIZE - 1; i >= 0; i--) { if (tablesize > ichdr.firstused) { sum += ichdr.freemap[i].size; continue; } if (!ichdr.freemap[i].size) continue; /* no space in this map */ tmp = entsize; if (ichdr.freemap[i].base < ichdr.firstused) tmp += sizeof(xfs_attr_leaf_entry_t); if (ichdr.freemap[i].size >= tmp) { tmp = xfs_attr3_leaf_add_work(bp, &ichdr, args, i); goto out_log_hdr; } sum += ichdr.freemap[i].size; } /* * If there are no holes in the address space of the block, * and we don't have enough freespace, then compaction will do us * no good and we should just give up. */ if (!ichdr.holes && sum < entsize) return -ENOSPC; /* * Compact the entries to coalesce free space. * This may change the hdr->count via dropping INCOMPLETE entries. */ xfs_attr3_leaf_compact(args, &ichdr, bp); /* * After compaction, the block is guaranteed to have only one * free region, in freemap[0]. If it is not big enough, give up. */ if (ichdr.freemap[0].size < (entsize + sizeof(xfs_attr_leaf_entry_t))) { tmp = -ENOSPC; goto out_log_hdr; } tmp = xfs_attr3_leaf_add_work(bp, &ichdr, args, 0); out_log_hdr: xfs_attr3_leaf_hdr_to_disk(args->geo, leaf, &ichdr); xfs_trans_log_buf(args->trans, bp, XFS_DA_LOGRANGE(leaf, &leaf->hdr, xfs_attr3_leaf_hdr_size(leaf))); return tmp; } /* * Add a name to a leaf attribute list structure. */ STATIC int xfs_attr3_leaf_add_work( struct xfs_buf *bp, struct xfs_attr3_icleaf_hdr *ichdr, struct xfs_da_args *args, int mapindex) { struct xfs_attr_leafblock *leaf; struct xfs_attr_leaf_entry *entry; struct xfs_attr_leaf_name_local *name_loc; struct xfs_attr_leaf_name_remote *name_rmt; struct xfs_mount *mp; int tmp; int i; trace_xfs_attr_leaf_add_work(args); leaf = bp->b_addr; ASSERT(mapindex >= 0 && mapindex < XFS_ATTR_LEAF_MAPSIZE); ASSERT(args->index >= 0 && args->index <= ichdr->count); /* * Force open some space in the entry array and fill it in. */ entry = &xfs_attr3_leaf_entryp(leaf)[args->index]; if (args->index < ichdr->count) { tmp = ichdr->count - args->index; tmp *= sizeof(xfs_attr_leaf_entry_t); memmove(entry + 1, entry, tmp); xfs_trans_log_buf(args->trans, bp, XFS_DA_LOGRANGE(leaf, entry, tmp + sizeof(*entry))); } ichdr->count++; /* * Allocate space for the new string (at the end of the run). */ mp = args->trans->t_mountp; ASSERT(ichdr->freemap[mapindex].base < args->geo->blksize); ASSERT((ichdr->freemap[mapindex].base & 0x3) == 0); ASSERT(ichdr->freemap[mapindex].size >= xfs_attr_leaf_newentsize(args, NULL)); ASSERT(ichdr->freemap[mapindex].size < args->geo->blksize); ASSERT((ichdr->freemap[mapindex].size & 0x3) == 0); ichdr->freemap[mapindex].size -= xfs_attr_leaf_newentsize(args, &tmp); entry->nameidx = cpu_to_be16(ichdr->freemap[mapindex].base + ichdr->freemap[mapindex].size); entry->hashval = cpu_to_be32(args->hashval); entry->flags = tmp ? XFS_ATTR_LOCAL : 0; entry->flags |= XFS_ATTR_NSP_ARGS_TO_ONDISK(args->flags); if (args->op_flags & XFS_DA_OP_RENAME) { entry->flags |= XFS_ATTR_INCOMPLETE; if ((args->blkno2 == args->blkno) && (args->index2 <= args->index)) { args->index2++; } } xfs_trans_log_buf(args->trans, bp, XFS_DA_LOGRANGE(leaf, entry, sizeof(*entry))); ASSERT((args->index == 0) || (be32_to_cpu(entry->hashval) >= be32_to_cpu((entry-1)->hashval))); ASSERT((args->index == ichdr->count - 1) || (be32_to_cpu(entry->hashval) <= be32_to_cpu((entry+1)->hashval))); /* * For "remote" attribute values, simply note that we need to * allocate space for the "remote" value. We can't actually * allocate the extents in this transaction, and we can't decide * which blocks they should be as we might allocate more blocks * as part of this transaction (a split operation for example). */ if (entry->flags & XFS_ATTR_LOCAL) { name_loc = xfs_attr3_leaf_name_local(leaf, args->index); name_loc->namelen = args->namelen; name_loc->valuelen = cpu_to_be16(args->valuelen); memcpy((char *)name_loc->nameval, args->name, args->namelen); memcpy((char *)&name_loc->nameval[args->namelen], args->value, be16_to_cpu(name_loc->valuelen)); } else { name_rmt = xfs_attr3_leaf_name_remote(leaf, args->index); name_rmt->namelen = args->namelen; memcpy((char *)name_rmt->name, args->name, args->namelen); entry->flags |= XFS_ATTR_INCOMPLETE; /* just in case */ name_rmt->valuelen = 0; name_rmt->valueblk = 0; args->rmtblkno = 1; args->rmtblkcnt = xfs_attr3_rmt_blocks(mp, args->valuelen); args->rmtvaluelen = args->valuelen; } xfs_trans_log_buf(args->trans, bp, XFS_DA_LOGRANGE(leaf, xfs_attr3_leaf_name(leaf, args->index), xfs_attr_leaf_entsize(leaf, args->index))); /* * Update the control info for this leaf node */ if (be16_to_cpu(entry->nameidx) < ichdr->firstused) ichdr->firstused = be16_to_cpu(entry->nameidx); ASSERT(ichdr->firstused >= ichdr->count * sizeof(xfs_attr_leaf_entry_t) + xfs_attr3_leaf_hdr_size(leaf)); tmp = (ichdr->count - 1) * sizeof(xfs_attr_leaf_entry_t) + xfs_attr3_leaf_hdr_size(leaf); for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; i++) { if (ichdr->freemap[i].base == tmp) { ichdr->freemap[i].base += sizeof(xfs_attr_leaf_entry_t); ichdr->freemap[i].size -= sizeof(xfs_attr_leaf_entry_t); } } ichdr->usedbytes += xfs_attr_leaf_entsize(leaf, args->index); return 0; } /* * Garbage collect a leaf attribute list block by copying it to a new buffer. */ STATIC void xfs_attr3_leaf_compact( struct xfs_da_args *args, struct xfs_attr3_icleaf_hdr *ichdr_dst, struct xfs_buf *bp) { struct xfs_attr_leafblock *leaf_src; struct xfs_attr_leafblock *leaf_dst; struct xfs_attr3_icleaf_hdr ichdr_src; struct xfs_trans *trans = args->trans; char *tmpbuffer; trace_xfs_attr_leaf_compact(args); tmpbuffer = kmem_alloc(args->geo->blksize, KM_SLEEP); memcpy(tmpbuffer, bp->b_addr, args->geo->blksize); memset(bp->b_addr, 0, args->geo->blksize); leaf_src = (xfs_attr_leafblock_t *)tmpbuffer; leaf_dst = bp->b_addr; /* * Copy the on-disk header back into the destination buffer to ensure * all the information in the header that is not part of the incore * header structure is preserved. */ memcpy(bp->b_addr, tmpbuffer, xfs_attr3_leaf_hdr_size(leaf_src)); /* Initialise the incore headers */ ichdr_src = *ichdr_dst; /* struct copy */ ichdr_dst->firstused = args->geo->blksize; ichdr_dst->usedbytes = 0; ichdr_dst->count = 0; ichdr_dst->holes = 0; ichdr_dst->freemap[0].base = xfs_attr3_leaf_hdr_size(leaf_src); ichdr_dst->freemap[0].size = ichdr_dst->firstused - ichdr_dst->freemap[0].base; /* write the header back to initialise the underlying buffer */ xfs_attr3_leaf_hdr_to_disk(args->geo, leaf_dst, ichdr_dst); /* * Copy all entry's in the same (sorted) order, * but allocate name/value pairs packed and in sequence. */ xfs_attr3_leaf_moveents(args, leaf_src, &ichdr_src, 0, leaf_dst, ichdr_dst, 0, ichdr_src.count); /* * this logs the entire buffer, but the caller must write the header * back to the buffer when it is finished modifying it. */ xfs_trans_log_buf(trans, bp, 0, args->geo->blksize - 1); kmem_free(tmpbuffer); } /* * Compare two leaf blocks "order". * Return 0 unless leaf2 should go before leaf1. */ static int xfs_attr3_leaf_order( struct xfs_buf *leaf1_bp, struct xfs_attr3_icleaf_hdr *leaf1hdr, struct xfs_buf *leaf2_bp, struct xfs_attr3_icleaf_hdr *leaf2hdr) { struct xfs_attr_leaf_entry *entries1; struct xfs_attr_leaf_entry *entries2; entries1 = xfs_attr3_leaf_entryp(leaf1_bp->b_addr); entries2 = xfs_attr3_leaf_entryp(leaf2_bp->b_addr); if (leaf1hdr->count > 0 && leaf2hdr->count > 0 && ((be32_to_cpu(entries2[0].hashval) < be32_to_cpu(entries1[0].hashval)) || (be32_to_cpu(entries2[leaf2hdr->count - 1].hashval) < be32_to_cpu(entries1[leaf1hdr->count - 1].hashval)))) { return 1; } return 0; } int xfs_attr_leaf_order( struct xfs_buf *leaf1_bp, struct xfs_buf *leaf2_bp) { struct xfs_attr3_icleaf_hdr ichdr1; struct xfs_attr3_icleaf_hdr ichdr2; struct xfs_mount *mp = leaf1_bp->b_target->bt_mount; xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &ichdr1, leaf1_bp->b_addr); xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &ichdr2, leaf2_bp->b_addr); return xfs_attr3_leaf_order(leaf1_bp, &ichdr1, leaf2_bp, &ichdr2); } /* * Redistribute the attribute list entries between two leaf nodes, * taking into account the size of the new entry. * * NOTE: if new block is empty, then it will get the upper half of the * old block. At present, all (one) callers pass in an empty second block. * * This code adjusts the args->index/blkno and args->index2/blkno2 fields * to match what it is doing in splitting the attribute leaf block. Those * values are used in "atomic rename" operations on attributes. Note that * the "new" and "old" values can end up in different blocks. */ STATIC void xfs_attr3_leaf_rebalance( struct xfs_da_state *state, struct xfs_da_state_blk *blk1, struct xfs_da_state_blk *blk2) { struct xfs_da_args *args; struct xfs_attr_leafblock *leaf1; struct xfs_attr_leafblock *leaf2; struct xfs_attr3_icleaf_hdr ichdr1; struct xfs_attr3_icleaf_hdr ichdr2; struct xfs_attr_leaf_entry *entries1; struct xfs_attr_leaf_entry *entries2; int count; int totallen; int max; int space; int swap; /* * Set up environment. */ ASSERT(blk1->magic == XFS_ATTR_LEAF_MAGIC); ASSERT(blk2->magic == XFS_ATTR_LEAF_MAGIC); leaf1 = blk1->bp->b_addr; leaf2 = blk2->bp->b_addr; xfs_attr3_leaf_hdr_from_disk(state->args->geo, &ichdr1, leaf1); xfs_attr3_leaf_hdr_from_disk(state->args->geo, &ichdr2, leaf2); ASSERT(ichdr2.count == 0); args = state->args; trace_xfs_attr_leaf_rebalance(args); /* * Check ordering of blocks, reverse if it makes things simpler. * * NOTE: Given that all (current) callers pass in an empty * second block, this code should never set "swap". */ swap = 0; if (xfs_attr3_leaf_order(blk1->bp, &ichdr1, blk2->bp, &ichdr2)) { struct xfs_da_state_blk *tmp_blk; struct xfs_attr3_icleaf_hdr tmp_ichdr; tmp_blk = blk1; blk1 = blk2; blk2 = tmp_blk; /* struct copies to swap them rather than reconverting */ tmp_ichdr = ichdr1; ichdr1 = ichdr2; ichdr2 = tmp_ichdr; leaf1 = blk1->bp->b_addr; leaf2 = blk2->bp->b_addr; swap = 1; } /* * Examine entries until we reduce the absolute difference in * byte usage between the two blocks to a minimum. Then get * the direction to copy and the number of elements to move. * * "inleaf" is true if the new entry should be inserted into blk1. * If "swap" is also true, then reverse the sense of "inleaf". */ state->inleaf = xfs_attr3_leaf_figure_balance(state, blk1, &ichdr1, blk2, &ichdr2, &count, &totallen); if (swap) state->inleaf = !state->inleaf; /* * Move any entries required from leaf to leaf: */ if (count < ichdr1.count) { /* * Figure the total bytes to be added to the destination leaf. */ /* number entries being moved */ count = ichdr1.count - count; space = ichdr1.usedbytes - totallen; space += count * sizeof(xfs_attr_leaf_entry_t); /* * leaf2 is the destination, compact it if it looks tight. */ max = ichdr2.firstused - xfs_attr3_leaf_hdr_size(leaf1); max -= ichdr2.count * sizeof(xfs_attr_leaf_entry_t); if (space > max) xfs_attr3_leaf_compact(args, &ichdr2, blk2->bp); /* * Move high entries from leaf1 to low end of leaf2. */ xfs_attr3_leaf_moveents(args, leaf1, &ichdr1, ichdr1.count - count, leaf2, &ichdr2, 0, count); } else if (count > ichdr1.count) { /* * I assert that since all callers pass in an empty * second buffer, this code should never execute. */ ASSERT(0); /* * Figure the total bytes to be added to the destination leaf. */ /* number entries being moved */ count -= ichdr1.count; space = totallen - ichdr1.usedbytes; space += count * sizeof(xfs_attr_leaf_entry_t); /* * leaf1 is the destination, compact it if it looks tight. */ max = ichdr1.firstused - xfs_attr3_leaf_hdr_size(leaf1); max -= ichdr1.count * sizeof(xfs_attr_leaf_entry_t); if (space > max) xfs_attr3_leaf_compact(args, &ichdr1, blk1->bp); /* * Move low entries from leaf2 to high end of leaf1. */ xfs_attr3_leaf_moveents(args, leaf2, &ichdr2, 0, leaf1, &ichdr1, ichdr1.count, count); } xfs_attr3_leaf_hdr_to_disk(state->args->geo, leaf1, &ichdr1); xfs_attr3_leaf_hdr_to_disk(state->args->geo, leaf2, &ichdr2); xfs_trans_log_buf(args->trans, blk1->bp, 0, args->geo->blksize - 1); xfs_trans_log_buf(args->trans, blk2->bp, 0, args->geo->blksize - 1); /* * Copy out last hashval in each block for B-tree code. */ entries1 = xfs_attr3_leaf_entryp(leaf1); entries2 = xfs_attr3_leaf_entryp(leaf2); blk1->hashval = be32_to_cpu(entries1[ichdr1.count - 1].hashval); blk2->hashval = be32_to_cpu(entries2[ichdr2.count - 1].hashval); /* * Adjust the expected index for insertion. * NOTE: this code depends on the (current) situation that the * second block was originally empty. * * If the insertion point moved to the 2nd block, we must adjust * the index. We must also track the entry just following the * new entry for use in an "atomic rename" operation, that entry * is always the "old" entry and the "new" entry is what we are * inserting. The index/blkno fields refer to the "old" entry, * while the index2/blkno2 fields refer to the "new" entry. */ if (blk1->index > ichdr1.count) { ASSERT(state->inleaf == 0); blk2->index = blk1->index - ichdr1.count; args->index = args->index2 = blk2->index; args->blkno = args->blkno2 = blk2->blkno; } else if (blk1->index == ichdr1.count) { if (state->inleaf) { args->index = blk1->index; args->blkno = blk1->blkno; args->index2 = 0; args->blkno2 = blk2->blkno; } else { /* * On a double leaf split, the original attr location * is already stored in blkno2/index2, so don't * overwrite it overwise we corrupt the tree. */ blk2->index = blk1->index - ichdr1.count; args->index = blk2->index; args->blkno = blk2->blkno; if (!state->extravalid) { /* * set the new attr location to match the old * one and let the higher level split code * decide where in the leaf to place it. */ args->index2 = blk2->index; args->blkno2 = blk2->blkno; } } } else { ASSERT(state->inleaf == 1); args->index = args->index2 = blk1->index; args->blkno = args->blkno2 = blk1->blkno; } } /* * Examine entries until we reduce the absolute difference in * byte usage between the two blocks to a minimum. * GROT: Is this really necessary? With other than a 512 byte blocksize, * GROT: there will always be enough room in either block for a new entry. * GROT: Do a double-split for this case? */ STATIC int xfs_attr3_leaf_figure_balance( struct xfs_da_state *state, struct xfs_da_state_blk *blk1, struct xfs_attr3_icleaf_hdr *ichdr1, struct xfs_da_state_blk *blk2, struct xfs_attr3_icleaf_hdr *ichdr2, int *countarg, int *usedbytesarg) { struct xfs_attr_leafblock *leaf1 = blk1->bp->b_addr; struct xfs_attr_leafblock *leaf2 = blk2->bp->b_addr; struct xfs_attr_leaf_entry *entry; int count; int max; int index; int totallen = 0; int half; int lastdelta; int foundit = 0; int tmp; /* * Examine entries until we reduce the absolute difference in * byte usage between the two blocks to a minimum. */ max = ichdr1->count + ichdr2->count; half = (max + 1) * sizeof(*entry); half += ichdr1->usedbytes + ichdr2->usedbytes + xfs_attr_leaf_newentsize(state->args, NULL); half /= 2; lastdelta = state->args->geo->blksize; entry = xfs_attr3_leaf_entryp(leaf1); for (count = index = 0; count < max; entry++, index++, count++) { #define XFS_ATTR_ABS(A) (((A) < 0) ? -(A) : (A)) /* * The new entry is in the first block, account for it. */ if (count == blk1->index) { tmp = totallen + sizeof(*entry) + xfs_attr_leaf_newentsize(state->args, NULL); if (XFS_ATTR_ABS(half - tmp) > lastdelta) break; lastdelta = XFS_ATTR_ABS(half - tmp); totallen = tmp; foundit = 1; } /* * Wrap around into the second block if necessary. */ if (count == ichdr1->count) { leaf1 = leaf2; entry = xfs_attr3_leaf_entryp(leaf1); index = 0; } /* * Figure out if next leaf entry would be too much. */ tmp = totallen + sizeof(*entry) + xfs_attr_leaf_entsize(leaf1, index); if (XFS_ATTR_ABS(half - tmp) > lastdelta) break; lastdelta = XFS_ATTR_ABS(half - tmp); totallen = tmp; #undef XFS_ATTR_ABS } /* * Calculate the number of usedbytes that will end up in lower block. * If new entry not in lower block, fix up the count. */ totallen -= count * sizeof(*entry); if (foundit) { totallen -= sizeof(*entry) + xfs_attr_leaf_newentsize(state->args, NULL); } *countarg = count; *usedbytesarg = totallen; return foundit; } /*======================================================================== * Routines used for shrinking the Btree. *========================================================================*/ /* * Check a leaf block and its neighbors to see if the block should be * collapsed into one or the other neighbor. Always keep the block * with the smaller block number. * If the current block is over 50% full, don't try to join it, return 0. * If the block is empty, fill in the state structure and return 2. * If it can be collapsed, fill in the state structure and return 1. * If nothing can be done, return 0. * * GROT: allow for INCOMPLETE entries in calculation. */ int xfs_attr3_leaf_toosmall( struct xfs_da_state *state, int *action) { struct xfs_attr_leafblock *leaf; struct xfs_da_state_blk *blk; struct xfs_attr3_icleaf_hdr ichdr; struct xfs_buf *bp; xfs_dablk_t blkno; int bytes; int forward; int error; int retval; int i; trace_xfs_attr_leaf_toosmall(state->args); /* * Check for the degenerate case of the block being over 50% full. * If so, it's not worth even looking to see if we might be able * to coalesce with a sibling. */ blk = &state->path.blk[ state->path.active-1 ]; leaf = blk->bp->b_addr; xfs_attr3_leaf_hdr_from_disk(state->args->geo, &ichdr, leaf); bytes = xfs_attr3_leaf_hdr_size(leaf) + ichdr.count * sizeof(xfs_attr_leaf_entry_t) + ichdr.usedbytes; if (bytes > (state->args->geo->blksize >> 1)) { *action = 0; /* blk over 50%, don't try to join */ return 0; } /* * Check for the degenerate case of the block being empty. * If the block is empty, we'll simply delete it, no need to * coalesce it with a sibling block. We choose (arbitrarily) * to merge with the forward block unless it is NULL. */ if (ichdr.count == 0) { /* * Make altpath point to the block we want to keep and * path point to the block we want to drop (this one). */ forward = (ichdr.forw != 0); memcpy(&state->altpath, &state->path, sizeof(state->path)); error = xfs_da3_path_shift(state, &state->altpath, forward, 0, &retval); if (error) return error; if (retval) { *action = 0; } else { *action = 2; } return 0; } /* * Examine each sibling block to see if we can coalesce with * at least 25% free space to spare. We need to figure out * whether to merge with the forward or the backward block. * We prefer coalescing with the lower numbered sibling so as * to shrink an attribute list over time. */ /* start with smaller blk num */ forward = ichdr.forw < ichdr.back; for (i = 0; i < 2; forward = !forward, i++) { struct xfs_attr3_icleaf_hdr ichdr2; if (forward) blkno = ichdr.forw; else blkno = ichdr.back; if (blkno == 0) continue; error = xfs_attr3_leaf_read(state->args->trans, state->args->dp, blkno, -1, &bp); if (error) return error; xfs_attr3_leaf_hdr_from_disk(state->args->geo, &ichdr2, bp->b_addr); bytes = state->args->geo->blksize - (state->args->geo->blksize >> 2) - ichdr.usedbytes - ichdr2.usedbytes - ((ichdr.count + ichdr2.count) * sizeof(xfs_attr_leaf_entry_t)) - xfs_attr3_leaf_hdr_size(leaf); xfs_trans_brelse(state->args->trans, bp); if (bytes >= 0) break; /* fits with at least 25% to spare */ } if (i >= 2) { *action = 0; return 0; } /* * Make altpath point to the block we want to keep (the lower * numbered block) and path point to the block we want to drop. */ memcpy(&state->altpath, &state->path, sizeof(state->path)); if (blkno < blk->blkno) { error = xfs_da3_path_shift(state, &state->altpath, forward, 0, &retval); } else { error = xfs_da3_path_shift(state, &state->path, forward, 0, &retval); } if (error) return error; if (retval) { *action = 0; } else { *action = 1; } return 0; } /* * Remove a name from the leaf attribute list structure. * * Return 1 if leaf is less than 37% full, 0 if >= 37% full. * If two leaves are 37% full, when combined they will leave 25% free. */ int xfs_attr3_leaf_remove( struct xfs_buf *bp, struct xfs_da_args *args) { struct xfs_attr_leafblock *leaf; struct xfs_attr3_icleaf_hdr ichdr; struct xfs_attr_leaf_entry *entry; int before; int after; int smallest; int entsize; int tablesize; int tmp; int i; trace_xfs_attr_leaf_remove(args); leaf = bp->b_addr; xfs_attr3_leaf_hdr_from_disk(args->geo, &ichdr, leaf); ASSERT(ichdr.count > 0 && ichdr.count < args->geo->blksize / 8); ASSERT(args->index >= 0 && args->index < ichdr.count); ASSERT(ichdr.firstused >= ichdr.count * sizeof(*entry) + xfs_attr3_leaf_hdr_size(leaf)); entry = &xfs_attr3_leaf_entryp(leaf)[args->index]; ASSERT(be16_to_cpu(entry->nameidx) >= ichdr.firstused); ASSERT(be16_to_cpu(entry->nameidx) < args->geo->blksize); /* * Scan through free region table: * check for adjacency of free'd entry with an existing one, * find smallest free region in case we need to replace it, * adjust any map that borders the entry table, */ tablesize = ichdr.count * sizeof(xfs_attr_leaf_entry_t) + xfs_attr3_leaf_hdr_size(leaf); tmp = ichdr.freemap[0].size; before = after = -1; smallest = XFS_ATTR_LEAF_MAPSIZE - 1; entsize = xfs_attr_leaf_entsize(leaf, args->index); for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; i++) { ASSERT(ichdr.freemap[i].base < args->geo->blksize); ASSERT(ichdr.freemap[i].size < args->geo->blksize); if (ichdr.freemap[i].base == tablesize) { ichdr.freemap[i].base -= sizeof(xfs_attr_leaf_entry_t); ichdr.freemap[i].size += sizeof(xfs_attr_leaf_entry_t); } if (ichdr.freemap[i].base + ichdr.freemap[i].size == be16_to_cpu(entry->nameidx)) { before = i; } else if (ichdr.freemap[i].base == (be16_to_cpu(entry->nameidx) + entsize)) { after = i; } else if (ichdr.freemap[i].size < tmp) { tmp = ichdr.freemap[i].size; smallest = i; } } /* * Coalesce adjacent freemap regions, * or replace the smallest region. */ if ((before >= 0) || (after >= 0)) { if ((before >= 0) && (after >= 0)) { ichdr.freemap[before].size += entsize; ichdr.freemap[before].size += ichdr.freemap[after].size; ichdr.freemap[after].base = 0; ichdr.freemap[after].size = 0; } else if (before >= 0) { ichdr.freemap[before].size += entsize; } else { ichdr.freemap[after].base = be16_to_cpu(entry->nameidx); ichdr.freemap[after].size += entsize; } } else { /* * Replace smallest region (if it is smaller than free'd entry) */ if (ichdr.freemap[smallest].size < entsize) { ichdr.freemap[smallest].base = be16_to_cpu(entry->nameidx); ichdr.freemap[smallest].size = entsize; } } /* * Did we remove the first entry? */ if (be16_to_cpu(entry->nameidx) == ichdr.firstused) smallest = 1; else smallest = 0; /* * Compress the remaining entries and zero out the removed stuff. */ memset(xfs_attr3_leaf_name(leaf, args->index), 0, entsize); ichdr.usedbytes -= entsize; xfs_trans_log_buf(args->trans, bp, XFS_DA_LOGRANGE(leaf, xfs_attr3_leaf_name(leaf, args->index), entsize)); tmp = (ichdr.count - args->index) * sizeof(xfs_attr_leaf_entry_t); memmove(entry, entry + 1, tmp); ichdr.count--; xfs_trans_log_buf(args->trans, bp, XFS_DA_LOGRANGE(leaf, entry, tmp + sizeof(xfs_attr_leaf_entry_t))); entry = &xfs_attr3_leaf_entryp(leaf)[ichdr.count]; memset(entry, 0, sizeof(xfs_attr_leaf_entry_t)); /* * If we removed the first entry, re-find the first used byte * in the name area. Note that if the entry was the "firstused", * then we don't have a "hole" in our block resulting from * removing the name. */ if (smallest) { tmp = args->geo->blksize; entry = xfs_attr3_leaf_entryp(leaf); for (i = ichdr.count - 1; i >= 0; entry++, i--) { ASSERT(be16_to_cpu(entry->nameidx) >= ichdr.firstused); ASSERT(be16_to_cpu(entry->nameidx) < args->geo->blksize); if (be16_to_cpu(entry->nameidx) < tmp) tmp = be16_to_cpu(entry->nameidx); } ichdr.firstused = tmp; ASSERT(ichdr.firstused != 0); } else { ichdr.holes = 1; /* mark as needing compaction */ } xfs_attr3_leaf_hdr_to_disk(args->geo, leaf, &ichdr); xfs_trans_log_buf(args->trans, bp, XFS_DA_LOGRANGE(leaf, &leaf->hdr, xfs_attr3_leaf_hdr_size(leaf))); /* * Check if leaf is less than 50% full, caller may want to * "join" the leaf with a sibling if so. */ tmp = ichdr.usedbytes + xfs_attr3_leaf_hdr_size(leaf) + ichdr.count * sizeof(xfs_attr_leaf_entry_t); return tmp < args->geo->magicpct; /* leaf is < 37% full */ } /* * Move all the attribute list entries from drop_leaf into save_leaf. */ void xfs_attr3_leaf_unbalance( struct xfs_da_state *state, struct xfs_da_state_blk *drop_blk, struct xfs_da_state_blk *save_blk) { struct xfs_attr_leafblock *drop_leaf = drop_blk->bp->b_addr; struct xfs_attr_leafblock *save_leaf = save_blk->bp->b_addr; struct xfs_attr3_icleaf_hdr drophdr; struct xfs_attr3_icleaf_hdr savehdr; struct xfs_attr_leaf_entry *entry; trace_xfs_attr_leaf_unbalance(state->args); drop_leaf = drop_blk->bp->b_addr; save_leaf = save_blk->bp->b_addr; xfs_attr3_leaf_hdr_from_disk(state->args->geo, &drophdr, drop_leaf); xfs_attr3_leaf_hdr_from_disk(state->args->geo, &savehdr, save_leaf); entry = xfs_attr3_leaf_entryp(drop_leaf); /* * Save last hashval from dying block for later Btree fixup. */ drop_blk->hashval = be32_to_cpu(entry[drophdr.count - 1].hashval); /* * Check if we need a temp buffer, or can we do it in place. * Note that we don't check "leaf" for holes because we will * always be dropping it, toosmall() decided that for us already. */ if (savehdr.holes == 0) { /* * dest leaf has no holes, so we add there. May need * to make some room in the entry array. */ if (xfs_attr3_leaf_order(save_blk->bp, &savehdr, drop_blk->bp, &drophdr)) { xfs_attr3_leaf_moveents(state->args, drop_leaf, &drophdr, 0, save_leaf, &savehdr, 0, drophdr.count); } else { xfs_attr3_leaf_moveents(state->args, drop_leaf, &drophdr, 0, save_leaf, &savehdr, savehdr.count, drophdr.count); } } else { /* * Destination has holes, so we make a temporary copy * of the leaf and add them both to that. */ struct xfs_attr_leafblock *tmp_leaf; struct xfs_attr3_icleaf_hdr tmphdr; tmp_leaf = kmem_zalloc(state->args->geo->blksize, KM_SLEEP); /* * Copy the header into the temp leaf so that all the stuff * not in the incore header is present and gets copied back in * once we've moved all the entries. */ memcpy(tmp_leaf, save_leaf, xfs_attr3_leaf_hdr_size(save_leaf)); memset(&tmphdr, 0, sizeof(tmphdr)); tmphdr.magic = savehdr.magic; tmphdr.forw = savehdr.forw; tmphdr.back = savehdr.back; tmphdr.firstused = state->args->geo->blksize; /* write the header to the temp buffer to initialise it */ xfs_attr3_leaf_hdr_to_disk(state->args->geo, tmp_leaf, &tmphdr); if (xfs_attr3_leaf_order(save_blk->bp, &savehdr, drop_blk->bp, &drophdr)) { xfs_attr3_leaf_moveents(state->args, drop_leaf, &drophdr, 0, tmp_leaf, &tmphdr, 0, drophdr.count); xfs_attr3_leaf_moveents(state->args, save_leaf, &savehdr, 0, tmp_leaf, &tmphdr, tmphdr.count, savehdr.count); } else { xfs_attr3_leaf_moveents(state->args, save_leaf, &savehdr, 0, tmp_leaf, &tmphdr, 0, savehdr.count); xfs_attr3_leaf_moveents(state->args, drop_leaf, &drophdr, 0, tmp_leaf, &tmphdr, tmphdr.count, drophdr.count); } memcpy(save_leaf, tmp_leaf, state->args->geo->blksize); savehdr = tmphdr; /* struct copy */ kmem_free(tmp_leaf); } xfs_attr3_leaf_hdr_to_disk(state->args->geo, save_leaf, &savehdr); xfs_trans_log_buf(state->args->trans, save_blk->bp, 0, state->args->geo->blksize - 1); /* * Copy out last hashval in each block for B-tree code. */ entry = xfs_attr3_leaf_entryp(save_leaf); save_blk->hashval = be32_to_cpu(entry[savehdr.count - 1].hashval); } /*======================================================================== * Routines used for finding things in the Btree. *========================================================================*/ /* * Look up a name in a leaf attribute list structure. * This is the internal routine, it uses the caller's buffer. * * Note that duplicate keys are allowed, but only check within the * current leaf node. The Btree code must check in adjacent leaf nodes. * * Return in args->index the index into the entry[] array of either * the found entry, or where the entry should have been (insert before * that entry). * * Don't change the args->value unless we find the attribute. */ int xfs_attr3_leaf_lookup_int( struct xfs_buf *bp, struct xfs_da_args *args) { struct xfs_attr_leafblock *leaf; struct xfs_attr3_icleaf_hdr ichdr; struct xfs_attr_leaf_entry *entry; struct xfs_attr_leaf_entry *entries; struct xfs_attr_leaf_name_local *name_loc; struct xfs_attr_leaf_name_remote *name_rmt; xfs_dahash_t hashval; int probe; int span; trace_xfs_attr_leaf_lookup(args); leaf = bp->b_addr; xfs_attr3_leaf_hdr_from_disk(args->geo, &ichdr, leaf); entries = xfs_attr3_leaf_entryp(leaf); ASSERT(ichdr.count < args->geo->blksize / 8); /* * Binary search. (note: small blocks will skip this loop) */ hashval = args->hashval; probe = span = ichdr.count / 2; for (entry = &entries[probe]; span > 4; entry = &entries[probe]) { span /= 2; if (be32_to_cpu(entry->hashval) < hashval) probe += span; else if (be32_to_cpu(entry->hashval) > hashval) probe -= span; else break; } ASSERT(probe >= 0 && (!ichdr.count || probe < ichdr.count)); ASSERT(span <= 4 || be32_to_cpu(entry->hashval) == hashval); /* * Since we may have duplicate hashval's, find the first matching * hashval in the leaf. */ while (probe > 0 && be32_to_cpu(entry->hashval) >= hashval) { entry--; probe--; } while (probe < ichdr.count && be32_to_cpu(entry->hashval) < hashval) { entry++; probe++; } if (probe == ichdr.count || be32_to_cpu(entry->hashval) != hashval) { args->index = probe; return -ENOATTR; } /* * Duplicate keys may be present, so search all of them for a match. */ for (; probe < ichdr.count && (be32_to_cpu(entry->hashval) == hashval); entry++, probe++) { /* * GROT: Add code to remove incomplete entries. */ /* * If we are looking for INCOMPLETE entries, show only those. * If we are looking for complete entries, show only those. */ if ((args->flags & XFS_ATTR_INCOMPLETE) != (entry->flags & XFS_ATTR_INCOMPLETE)) { continue; } if (entry->flags & XFS_ATTR_LOCAL) { name_loc = xfs_attr3_leaf_name_local(leaf, probe); if (name_loc->namelen != args->namelen) continue; if (memcmp(args->name, name_loc->nameval, args->namelen) != 0) continue; if (!xfs_attr_namesp_match(args->flags, entry->flags)) continue; args->index = probe; return -EEXIST; } else { name_rmt = xfs_attr3_leaf_name_remote(leaf, probe); if (name_rmt->namelen != args->namelen) continue; if (memcmp(args->name, name_rmt->name, args->namelen) != 0) continue; if (!xfs_attr_namesp_match(args->flags, entry->flags)) continue; args->index = probe; args->rmtvaluelen = be32_to_cpu(name_rmt->valuelen); args->rmtblkno = be32_to_cpu(name_rmt->valueblk); args->rmtblkcnt = xfs_attr3_rmt_blocks( args->dp->i_mount, args->rmtvaluelen); return -EEXIST; } } args->index = probe; return -ENOATTR; } /* * Get the value associated with an attribute name from a leaf attribute * list structure. */ int xfs_attr3_leaf_getvalue( struct xfs_buf *bp, struct xfs_da_args *args) { struct xfs_attr_leafblock *leaf; struct xfs_attr3_icleaf_hdr ichdr; struct xfs_attr_leaf_entry *entry; struct xfs_attr_leaf_name_local *name_loc; struct xfs_attr_leaf_name_remote *name_rmt; int valuelen; leaf = bp->b_addr; xfs_attr3_leaf_hdr_from_disk(args->geo, &ichdr, leaf); ASSERT(ichdr.count < args->geo->blksize / 8); ASSERT(args->index < ichdr.count); entry = &xfs_attr3_leaf_entryp(leaf)[args->index]; if (entry->flags & XFS_ATTR_LOCAL) { name_loc = xfs_attr3_leaf_name_local(leaf, args->index); ASSERT(name_loc->namelen == args->namelen); ASSERT(memcmp(args->name, name_loc->nameval, args->namelen) == 0); valuelen = be16_to_cpu(name_loc->valuelen); if (args->flags & ATTR_KERNOVAL) { args->valuelen = valuelen; return 0; } if (args->valuelen < valuelen) { args->valuelen = valuelen; return -ERANGE; } args->valuelen = valuelen; memcpy(args->value, &name_loc->nameval[args->namelen], valuelen); } else { name_rmt = xfs_attr3_leaf_name_remote(leaf, args->index); ASSERT(name_rmt->namelen == args->namelen); ASSERT(memcmp(args->name, name_rmt->name, args->namelen) == 0); args->rmtvaluelen = be32_to_cpu(name_rmt->valuelen); args->rmtblkno = be32_to_cpu(name_rmt->valueblk); args->rmtblkcnt = xfs_attr3_rmt_blocks(args->dp->i_mount, args->rmtvaluelen); if (args->flags & ATTR_KERNOVAL) { args->valuelen = args->rmtvaluelen; return 0; } if (args->valuelen < args->rmtvaluelen) { args->valuelen = args->rmtvaluelen; return -ERANGE; } args->valuelen = args->rmtvaluelen; } return 0; } /*======================================================================== * Utility routines. *========================================================================*/ /* * Move the indicated entries from one leaf to another. * NOTE: this routine modifies both source and destination leaves. */ /*ARGSUSED*/ STATIC void xfs_attr3_leaf_moveents( struct xfs_da_args *args, struct xfs_attr_leafblock *leaf_s, struct xfs_attr3_icleaf_hdr *ichdr_s, int start_s, struct xfs_attr_leafblock *leaf_d, struct xfs_attr3_icleaf_hdr *ichdr_d, int start_d, int count) { struct xfs_attr_leaf_entry *entry_s; struct xfs_attr_leaf_entry *entry_d; int desti; int tmp; int i; /* * Check for nothing to do. */ if (count == 0) return; /* * Set up environment. */ ASSERT(ichdr_s->magic == XFS_ATTR_LEAF_MAGIC || ichdr_s->magic == XFS_ATTR3_LEAF_MAGIC); ASSERT(ichdr_s->magic == ichdr_d->magic); ASSERT(ichdr_s->count > 0 && ichdr_s->count < args->geo->blksize / 8); ASSERT(ichdr_s->firstused >= (ichdr_s->count * sizeof(*entry_s)) + xfs_attr3_leaf_hdr_size(leaf_s)); ASSERT(ichdr_d->count < args->geo->blksize / 8); ASSERT(ichdr_d->firstused >= (ichdr_d->count * sizeof(*entry_d)) + xfs_attr3_leaf_hdr_size(leaf_d)); ASSERT(start_s < ichdr_s->count); ASSERT(start_d <= ichdr_d->count); ASSERT(count <= ichdr_s->count); /* * Move the entries in the destination leaf up to make a hole? */ if (start_d < ichdr_d->count) { tmp = ichdr_d->count - start_d; tmp *= sizeof(xfs_attr_leaf_entry_t); entry_s = &xfs_attr3_leaf_entryp(leaf_d)[start_d]; entry_d = &xfs_attr3_leaf_entryp(leaf_d)[start_d + count]; memmove(entry_d, entry_s, tmp); } /* * Copy all entry's in the same (sorted) order, * but allocate attribute info packed and in sequence. */ entry_s = &xfs_attr3_leaf_entryp(leaf_s)[start_s]; entry_d = &xfs_attr3_leaf_entryp(leaf_d)[start_d]; desti = start_d; for (i = 0; i < count; entry_s++, entry_d++, desti++, i++) { ASSERT(be16_to_cpu(entry_s->nameidx) >= ichdr_s->firstused); tmp = xfs_attr_leaf_entsize(leaf_s, start_s + i); #ifdef GROT /* * Code to drop INCOMPLETE entries. Difficult to use as we * may also need to change the insertion index. Code turned * off for 6.2, should be revisited later. */ if (entry_s->flags & XFS_ATTR_INCOMPLETE) { /* skip partials? */ memset(xfs_attr3_leaf_name(leaf_s, start_s + i), 0, tmp); ichdr_s->usedbytes -= tmp; ichdr_s->count -= 1; entry_d--; /* to compensate for ++ in loop hdr */ desti--; if ((start_s + i) < offset) result++; /* insertion index adjustment */ } else { #endif /* GROT */ ichdr_d->firstused -= tmp; /* both on-disk, don't endian flip twice */ entry_d->hashval = entry_s->hashval; entry_d->nameidx = cpu_to_be16(ichdr_d->firstused); entry_d->flags = entry_s->flags; ASSERT(be16_to_cpu(entry_d->nameidx) + tmp <= args->geo->blksize); memmove(xfs_attr3_leaf_name(leaf_d, desti), xfs_attr3_leaf_name(leaf_s, start_s + i), tmp); ASSERT(be16_to_cpu(entry_s->nameidx) + tmp <= args->geo->blksize); memset(xfs_attr3_leaf_name(leaf_s, start_s + i), 0, tmp); ichdr_s->usedbytes -= tmp; ichdr_d->usedbytes += tmp; ichdr_s->count -= 1; ichdr_d->count += 1; tmp = ichdr_d->count * sizeof(xfs_attr_leaf_entry_t) + xfs_attr3_leaf_hdr_size(leaf_d); ASSERT(ichdr_d->firstused >= tmp); #ifdef GROT } #endif /* GROT */ } /* * Zero out the entries we just copied. */ if (start_s == ichdr_s->count) { tmp = count * sizeof(xfs_attr_leaf_entry_t); entry_s = &xfs_attr3_leaf_entryp(leaf_s)[start_s]; ASSERT(((char *)entry_s + tmp) <= ((char *)leaf_s + args->geo->blksize)); memset(entry_s, 0, tmp); } else { /* * Move the remaining entries down to fill the hole, * then zero the entries at the top. */ tmp = (ichdr_s->count - count) * sizeof(xfs_attr_leaf_entry_t); entry_s = &xfs_attr3_leaf_entryp(leaf_s)[start_s + count]; entry_d = &xfs_attr3_leaf_entryp(leaf_s)[start_s]; memmove(entry_d, entry_s, tmp); tmp = count * sizeof(xfs_attr_leaf_entry_t); entry_s = &xfs_attr3_leaf_entryp(leaf_s)[ichdr_s->count]; ASSERT(((char *)entry_s + tmp) <= ((char *)leaf_s + args->geo->blksize)); memset(entry_s, 0, tmp); } /* * Fill in the freemap information */ ichdr_d->freemap[0].base = xfs_attr3_leaf_hdr_size(leaf_d); ichdr_d->freemap[0].base += ichdr_d->count * sizeof(xfs_attr_leaf_entry_t); ichdr_d->freemap[0].size = ichdr_d->firstused - ichdr_d->freemap[0].base; ichdr_d->freemap[1].base = 0; ichdr_d->freemap[2].base = 0; ichdr_d->freemap[1].size = 0; ichdr_d->freemap[2].size = 0; ichdr_s->holes = 1; /* leaf may not be compact */ } /* * Pick up the last hashvalue from a leaf block. */ xfs_dahash_t xfs_attr_leaf_lasthash( struct xfs_buf *bp, int *count) { struct xfs_attr3_icleaf_hdr ichdr; struct xfs_attr_leaf_entry *entries; struct xfs_mount *mp = bp->b_target->bt_mount; xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &ichdr, bp->b_addr); entries = xfs_attr3_leaf_entryp(bp->b_addr); if (count) *count = ichdr.count; if (!ichdr.count) return 0; return be32_to_cpu(entries[ichdr.count - 1].hashval); } /* * Calculate the number of bytes used to store the indicated attribute * (whether local or remote only calculate bytes in this block). */ STATIC int xfs_attr_leaf_entsize(xfs_attr_leafblock_t *leaf, int index) { struct xfs_attr_leaf_entry *entries; xfs_attr_leaf_name_local_t *name_loc; xfs_attr_leaf_name_remote_t *name_rmt; int size; entries = xfs_attr3_leaf_entryp(leaf); if (entries[index].flags & XFS_ATTR_LOCAL) { name_loc = xfs_attr3_leaf_name_local(leaf, index); size = xfs_attr_leaf_entsize_local(name_loc->namelen, be16_to_cpu(name_loc->valuelen)); } else { name_rmt = xfs_attr3_leaf_name_remote(leaf, index); size = xfs_attr_leaf_entsize_remote(name_rmt->namelen); } return size; } /* * Calculate the number of bytes that would be required to store the new * attribute (whether local or remote only calculate bytes in this block). * This routine decides as a side effect whether the attribute will be * a "local" or a "remote" attribute. */ int xfs_attr_leaf_newentsize( struct xfs_da_args *args, int *local) { int size; size = xfs_attr_leaf_entsize_local(args->namelen, args->valuelen); if (size < xfs_attr_leaf_entsize_local_max(args->geo->blksize)) { if (local) *local = 1; return size; } if (local) *local = 0; return xfs_attr_leaf_entsize_remote(args->namelen); } /*======================================================================== * Manage the INCOMPLETE flag in a leaf entry *========================================================================*/ /* * Clear the INCOMPLETE flag on an entry in a leaf block. */ int xfs_attr3_leaf_clearflag( struct xfs_da_args *args) { struct xfs_attr_leafblock *leaf; struct xfs_attr_leaf_entry *entry; struct xfs_attr_leaf_name_remote *name_rmt; struct xfs_buf *bp; int error; #ifdef DEBUG struct xfs_attr3_icleaf_hdr ichdr; xfs_attr_leaf_name_local_t *name_loc; int namelen; char *name; #endif /* DEBUG */ trace_xfs_attr_leaf_clearflag(args); /* * Set up the operation. */ error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp); if (error) return error; leaf = bp->b_addr; entry = &xfs_attr3_leaf_entryp(leaf)[args->index]; ASSERT(entry->flags & XFS_ATTR_INCOMPLETE); #ifdef DEBUG xfs_attr3_leaf_hdr_from_disk(args->geo, &ichdr, leaf); ASSERT(args->index < ichdr.count); ASSERT(args->index >= 0); if (entry->flags & XFS_ATTR_LOCAL) { name_loc = xfs_attr3_leaf_name_local(leaf, args->index); namelen = name_loc->namelen; name = (char *)name_loc->nameval; } else { name_rmt = xfs_attr3_leaf_name_remote(leaf, args->index); namelen = name_rmt->namelen; name = (char *)name_rmt->name; } ASSERT(be32_to_cpu(entry->hashval) == args->hashval); ASSERT(namelen == args->namelen); ASSERT(memcmp(name, args->name, namelen) == 0); #endif /* DEBUG */ entry->flags &= ~XFS_ATTR_INCOMPLETE; xfs_trans_log_buf(args->trans, bp, XFS_DA_LOGRANGE(leaf, entry, sizeof(*entry))); if (args->rmtblkno) { ASSERT((entry->flags & XFS_ATTR_LOCAL) == 0); name_rmt = xfs_attr3_leaf_name_remote(leaf, args->index); name_rmt->valueblk = cpu_to_be32(args->rmtblkno); name_rmt->valuelen = cpu_to_be32(args->rmtvaluelen); xfs_trans_log_buf(args->trans, bp, XFS_DA_LOGRANGE(leaf, name_rmt, sizeof(*name_rmt))); } /* * Commit the flag value change and start the next trans in series. */ return xfs_trans_roll(&args->trans, args->dp); } /* * Set the INCOMPLETE flag on an entry in a leaf block. */ int xfs_attr3_leaf_setflag( struct xfs_da_args *args) { struct xfs_attr_leafblock *leaf; struct xfs_attr_leaf_entry *entry; struct xfs_attr_leaf_name_remote *name_rmt; struct xfs_buf *bp; int error; #ifdef DEBUG struct xfs_attr3_icleaf_hdr ichdr; #endif trace_xfs_attr_leaf_setflag(args); /* * Set up the operation. */ error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp); if (error) return error; leaf = bp->b_addr; #ifdef DEBUG xfs_attr3_leaf_hdr_from_disk(args->geo, &ichdr, leaf); ASSERT(args->index < ichdr.count); ASSERT(args->index >= 0); #endif entry = &xfs_attr3_leaf_entryp(leaf)[args->index]; ASSERT((entry->flags & XFS_ATTR_INCOMPLETE) == 0); entry->flags |= XFS_ATTR_INCOMPLETE; xfs_trans_log_buf(args->trans, bp, XFS_DA_LOGRANGE(leaf, entry, sizeof(*entry))); if ((entry->flags & XFS_ATTR_LOCAL) == 0) { name_rmt = xfs_attr3_leaf_name_remote(leaf, args->index); name_rmt->valueblk = 0; name_rmt->valuelen = 0; xfs_trans_log_buf(args->trans, bp, XFS_DA_LOGRANGE(leaf, name_rmt, sizeof(*name_rmt))); } /* * Commit the flag value change and start the next trans in series. */ return xfs_trans_roll(&args->trans, args->dp); } /* * In a single transaction, clear the INCOMPLETE flag on the leaf entry * given by args->blkno/index and set the INCOMPLETE flag on the leaf * entry given by args->blkno2/index2. * * Note that they could be in different blocks, or in the same block. */ int xfs_attr3_leaf_flipflags( struct xfs_da_args *args) { struct xfs_attr_leafblock *leaf1; struct xfs_attr_leafblock *leaf2; struct xfs_attr_leaf_entry *entry1; struct xfs_attr_leaf_entry *entry2; struct xfs_attr_leaf_name_remote *name_rmt; struct xfs_buf *bp1; struct xfs_buf *bp2; int error; #ifdef DEBUG struct xfs_attr3_icleaf_hdr ichdr1; struct xfs_attr3_icleaf_hdr ichdr2; xfs_attr_leaf_name_local_t *name_loc; int namelen1, namelen2; char *name1, *name2; #endif /* DEBUG */ trace_xfs_attr_leaf_flipflags(args); /* * Read the block containing the "old" attr */ error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp1); if (error) return error; /* * Read the block containing the "new" attr, if it is different */ if (args->blkno2 != args->blkno) { error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno2, -1, &bp2); if (error) return error; } else { bp2 = bp1; } leaf1 = bp1->b_addr; entry1 = &xfs_attr3_leaf_entryp(leaf1)[args->index]; leaf2 = bp2->b_addr; entry2 = &xfs_attr3_leaf_entryp(leaf2)[args->index2]; #ifdef DEBUG xfs_attr3_leaf_hdr_from_disk(args->geo, &ichdr1, leaf1); ASSERT(args->index < ichdr1.count); ASSERT(args->index >= 0); xfs_attr3_leaf_hdr_from_disk(args->geo, &ichdr2, leaf2); ASSERT(args->index2 < ichdr2.count); ASSERT(args->index2 >= 0); if (entry1->flags & XFS_ATTR_LOCAL) { name_loc = xfs_attr3_leaf_name_local(leaf1, args->index); namelen1 = name_loc->namelen; name1 = (char *)name_loc->nameval; } else { name_rmt = xfs_attr3_leaf_name_remote(leaf1, args->index); namelen1 = name_rmt->namelen; name1 = (char *)name_rmt->name; } if (entry2->flags & XFS_ATTR_LOCAL) { name_loc = xfs_attr3_leaf_name_local(leaf2, args->index2); namelen2 = name_loc->namelen; name2 = (char *)name_loc->nameval; } else { name_rmt = xfs_attr3_leaf_name_remote(leaf2, args->index2); namelen2 = name_rmt->namelen; name2 = (char *)name_rmt->name; } ASSERT(be32_to_cpu(entry1->hashval) == be32_to_cpu(entry2->hashval)); ASSERT(namelen1 == namelen2); ASSERT(memcmp(name1, name2, namelen1) == 0); #endif /* DEBUG */ ASSERT(entry1->flags & XFS_ATTR_INCOMPLETE); ASSERT((entry2->flags & XFS_ATTR_INCOMPLETE) == 0); entry1->flags &= ~XFS_ATTR_INCOMPLETE; xfs_trans_log_buf(args->trans, bp1, XFS_DA_LOGRANGE(leaf1, entry1, sizeof(*entry1))); if (args->rmtblkno) { ASSERT((entry1->flags & XFS_ATTR_LOCAL) == 0); name_rmt = xfs_attr3_leaf_name_remote(leaf1, args->index); name_rmt->valueblk = cpu_to_be32(args->rmtblkno); name_rmt->valuelen = cpu_to_be32(args->rmtvaluelen); xfs_trans_log_buf(args->trans, bp1, XFS_DA_LOGRANGE(leaf1, name_rmt, sizeof(*name_rmt))); } entry2->flags |= XFS_ATTR_INCOMPLETE; xfs_trans_log_buf(args->trans, bp2, XFS_DA_LOGRANGE(leaf2, entry2, sizeof(*entry2))); if ((entry2->flags & XFS_ATTR_LOCAL) == 0) { name_rmt = xfs_attr3_leaf_name_remote(leaf2, args->index2); name_rmt->valueblk = 0; name_rmt->valuelen = 0; xfs_trans_log_buf(args->trans, bp2, XFS_DA_LOGRANGE(leaf2, name_rmt, sizeof(*name_rmt))); } /* * Commit the flag value change and start the next trans in series. */ error = xfs_trans_roll(&args->trans, args->dp); return error; } partclone-0.2.86/src/xfs/xfs_attr_leaf.h000066400000000000000000000101751262102574200201640ustar00rootroot00000000000000/* * Copyright (c) 2000,2002-2003,2005 Silicon Graphics, Inc. * Copyright (c) 2013 Red Hat, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __XFS_ATTR_LEAF_H__ #define __XFS_ATTR_LEAF_H__ struct attrlist; struct attrlist_cursor_kern; struct xfs_attr_list_context; struct xfs_da_args; struct xfs_da_state; struct xfs_da_state_blk; struct xfs_inode; struct xfs_trans; /* * Used to keep a list of "remote value" extents when unlinking an inode. */ typedef struct xfs_attr_inactive_list { xfs_dablk_t valueblk; /* block number of value bytes */ int valuelen; /* number of bytes in value */ } xfs_attr_inactive_list_t; /*======================================================================== * Function prototypes for the kernel. *========================================================================*/ /* * Internal routines when attribute fork size < XFS_LITINO(mp). */ void xfs_attr_shortform_create(struct xfs_da_args *args); void xfs_attr_shortform_add(struct xfs_da_args *args, int forkoff); int xfs_attr_shortform_lookup(struct xfs_da_args *args); int xfs_attr_shortform_getvalue(struct xfs_da_args *args); int xfs_attr_shortform_to_leaf(struct xfs_da_args *args); int xfs_attr_shortform_remove(struct xfs_da_args *args); int xfs_attr_shortform_list(struct xfs_attr_list_context *context); int xfs_attr_shortform_allfit(struct xfs_buf *bp, struct xfs_inode *dp); int xfs_attr_shortform_bytesfit(struct xfs_inode *dp, int bytes); void xfs_attr_fork_remove(struct xfs_inode *ip, struct xfs_trans *tp); /* * Internal routines when attribute fork size == XFS_LBSIZE(mp). */ int xfs_attr3_leaf_to_node(struct xfs_da_args *args); int xfs_attr3_leaf_to_shortform(struct xfs_buf *bp, struct xfs_da_args *args, int forkoff); int xfs_attr3_leaf_clearflag(struct xfs_da_args *args); int xfs_attr3_leaf_setflag(struct xfs_da_args *args); int xfs_attr3_leaf_flipflags(struct xfs_da_args *args); /* * Routines used for growing the Btree. */ int xfs_attr3_leaf_split(struct xfs_da_state *state, struct xfs_da_state_blk *oldblk, struct xfs_da_state_blk *newblk); int xfs_attr3_leaf_lookup_int(struct xfs_buf *leaf, struct xfs_da_args *args); int xfs_attr3_leaf_getvalue(struct xfs_buf *bp, struct xfs_da_args *args); int xfs_attr3_leaf_add(struct xfs_buf *leaf_buffer, struct xfs_da_args *args); int xfs_attr3_leaf_remove(struct xfs_buf *leaf_buffer, struct xfs_da_args *args); int xfs_attr3_leaf_list_int(struct xfs_buf *bp, struct xfs_attr_list_context *context); /* * Routines used for shrinking the Btree. */ int xfs_attr3_leaf_toosmall(struct xfs_da_state *state, int *retval); void xfs_attr3_leaf_unbalance(struct xfs_da_state *state, struct xfs_da_state_blk *drop_blk, struct xfs_da_state_blk *save_blk); int xfs_attr3_root_inactive(struct xfs_trans **trans, struct xfs_inode *dp); /* * Utility routines. */ xfs_dahash_t xfs_attr_leaf_lasthash(struct xfs_buf *bp, int *count); int xfs_attr_leaf_order(struct xfs_buf *leaf1_bp, struct xfs_buf *leaf2_bp); int xfs_attr_leaf_newentsize(struct xfs_da_args *args, int *local); int xfs_attr3_leaf_read(struct xfs_trans *tp, struct xfs_inode *dp, xfs_dablk_t bno, xfs_daddr_t mappedbno, struct xfs_buf **bpp); void xfs_attr3_leaf_hdr_from_disk(struct xfs_da_geometry *geo, struct xfs_attr3_icleaf_hdr *to, struct xfs_attr_leafblock *from); void xfs_attr3_leaf_hdr_to_disk(struct xfs_da_geometry *geo, struct xfs_attr_leafblock *to, struct xfs_attr3_icleaf_hdr *from); #endif /* __XFS_ATTR_LEAF_H__ */ partclone-0.2.86/src/xfs/xfs_attr_remote.c000066400000000000000000000371231262102574200205450ustar00rootroot00000000000000/* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * Copyright (c) 2013 Red Hat, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_bit.h" #include "xfs_mount.h" #include "xfs_da_format.h" #include "xfs_da_btree.h" #include "xfs_inode.h" #include "xfs_alloc.h" #include "xfs_trans.h" #include "xfs_bmap.h" #include "xfs_attr_leaf.h" #include "xfs_attr_remote.h" #include "xfs_trans_space.h" #include "xfs_trace.h" #include "xfs_cksum.h" #define ATTR_RMTVALUE_MAPSIZE 1 /* # of map entries at once */ /* * Each contiguous block has a header, so it is not just a simple attribute * length to FSB conversion. */ int xfs_attr3_rmt_blocks( struct xfs_mount *mp, int attrlen) { if (xfs_sb_version_hascrc(&mp->m_sb)) { int buflen = XFS_ATTR3_RMT_BUF_SPACE(mp, mp->m_sb.sb_blocksize); return (attrlen + buflen - 1) / buflen; } return XFS_B_TO_FSB(mp, attrlen); } /* * Checking of the remote attribute header is split into two parts. The verifier * does CRC, location and bounds checking, the unpacking function checks the * attribute parameters and owner. */ static bool xfs_attr3_rmt_hdr_ok( void *ptr, xfs_ino_t ino, uint32_t offset, uint32_t size, xfs_daddr_t bno) { struct xfs_attr3_rmt_hdr *rmt = ptr; if (bno != be64_to_cpu(rmt->rm_blkno)) return false; if (offset != be32_to_cpu(rmt->rm_offset)) return false; if (size != be32_to_cpu(rmt->rm_bytes)) return false; if (ino != be64_to_cpu(rmt->rm_owner)) return false; /* ok */ return true; } static bool xfs_attr3_rmt_verify( struct xfs_mount *mp, void *ptr, int fsbsize, xfs_daddr_t bno) { struct xfs_attr3_rmt_hdr *rmt = ptr; if (!xfs_sb_version_hascrc(&mp->m_sb)) return false; if (rmt->rm_magic != cpu_to_be32(XFS_ATTR3_RMT_MAGIC)) return false; if (!uuid_equal(&rmt->rm_uuid, &mp->m_sb.sb_meta_uuid)) return false; if (be64_to_cpu(rmt->rm_blkno) != bno) return false; if (be32_to_cpu(rmt->rm_bytes) > fsbsize - sizeof(*rmt)) return false; if (be32_to_cpu(rmt->rm_offset) + be32_to_cpu(rmt->rm_bytes) > XATTR_SIZE_MAX) return false; if (rmt->rm_owner == 0) return false; return true; } static void xfs_attr3_rmt_read_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_target->bt_mount; char *ptr; int len; xfs_daddr_t bno; int blksize = mp->m_attr_geo->blksize; /* no verification of non-crc buffers */ if (!xfs_sb_version_hascrc(&mp->m_sb)) return; ptr = bp->b_addr; bno = bp->b_bn; len = BBTOB(bp->b_length); ASSERT(len >= blksize); while (len > 0) { if (!xfs_verify_cksum(ptr, blksize, XFS_ATTR3_RMT_CRC_OFF)) { xfs_buf_ioerror(bp, -EFSBADCRC); break; } if (!xfs_attr3_rmt_verify(mp, ptr, blksize, bno)) { xfs_buf_ioerror(bp, -EFSCORRUPTED); break; } len -= blksize; ptr += blksize; bno += BTOBB(blksize); } if (bp->b_error) xfs_verifier_error(bp); else ASSERT(len == 0); } static void xfs_attr3_rmt_write_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_target->bt_mount; int blksize = mp->m_attr_geo->blksize; char *ptr; int len; xfs_daddr_t bno; /* no verification of non-crc buffers */ if (!xfs_sb_version_hascrc(&mp->m_sb)) return; ptr = bp->b_addr; bno = bp->b_bn; len = BBTOB(bp->b_length); ASSERT(len >= blksize); while (len > 0) { struct xfs_attr3_rmt_hdr *rmt = (struct xfs_attr3_rmt_hdr *)ptr; if (!xfs_attr3_rmt_verify(mp, ptr, blksize, bno)) { xfs_buf_ioerror(bp, -EFSCORRUPTED); xfs_verifier_error(bp); return; } /* * Ensure we aren't writing bogus LSNs to disk. See * xfs_attr3_rmt_hdr_set() for the explanation. */ if (rmt->rm_lsn != cpu_to_be64(NULLCOMMITLSN)) { xfs_buf_ioerror(bp, -EFSCORRUPTED); xfs_verifier_error(bp); return; } xfs_update_cksum(ptr, blksize, XFS_ATTR3_RMT_CRC_OFF); len -= blksize; ptr += blksize; bno += BTOBB(blksize); } ASSERT(len == 0); } const struct xfs_buf_ops xfs_attr3_rmt_buf_ops = { .verify_read = xfs_attr3_rmt_read_verify, .verify_write = xfs_attr3_rmt_write_verify, }; STATIC int xfs_attr3_rmt_hdr_set( struct xfs_mount *mp, void *ptr, xfs_ino_t ino, uint32_t offset, uint32_t size, xfs_daddr_t bno) { struct xfs_attr3_rmt_hdr *rmt = ptr; if (!xfs_sb_version_hascrc(&mp->m_sb)) return 0; rmt->rm_magic = cpu_to_be32(XFS_ATTR3_RMT_MAGIC); rmt->rm_offset = cpu_to_be32(offset); rmt->rm_bytes = cpu_to_be32(size); uuid_copy(&rmt->rm_uuid, &mp->m_sb.sb_meta_uuid); rmt->rm_owner = cpu_to_be64(ino); rmt->rm_blkno = cpu_to_be64(bno); /* * Remote attribute blocks are written synchronously, so we don't * have an LSN that we can stamp in them that makes any sense to log * recovery. To ensure that log recovery handles overwrites of these * blocks sanely (i.e. once they've been freed and reallocated as some * other type of metadata) we need to ensure that the LSN has a value * that tells log recovery to ignore the LSN and overwrite the buffer * with whatever is in it's log. To do this, we use the magic * NULLCOMMITLSN to indicate that the LSN is invalid. */ rmt->rm_lsn = cpu_to_be64(NULLCOMMITLSN); return sizeof(struct xfs_attr3_rmt_hdr); } /* * Helper functions to copy attribute data in and out of the one disk extents */ STATIC int xfs_attr_rmtval_copyout( struct xfs_mount *mp, struct xfs_buf *bp, xfs_ino_t ino, int *offset, int *valuelen, __uint8_t **dst) { char *src = bp->b_addr; xfs_daddr_t bno = bp->b_bn; int len = BBTOB(bp->b_length); int blksize = mp->m_attr_geo->blksize; ASSERT(len >= blksize); while (len > 0 && *valuelen > 0) { int hdr_size = 0; int byte_cnt = XFS_ATTR3_RMT_BUF_SPACE(mp, blksize); byte_cnt = min(*valuelen, byte_cnt); if (xfs_sb_version_hascrc(&mp->m_sb)) { if (!xfs_attr3_rmt_hdr_ok(src, ino, *offset, byte_cnt, bno)) { xfs_alert(mp, "remote attribute header mismatch bno/off/len/owner (0x%llx/0x%x/Ox%x/0x%llx)", bno, *offset, byte_cnt, ino); return -EFSCORRUPTED; } hdr_size = sizeof(struct xfs_attr3_rmt_hdr); } memcpy(*dst, src + hdr_size, byte_cnt); /* roll buffer forwards */ len -= blksize; src += blksize; bno += BTOBB(blksize); /* roll attribute data forwards */ *valuelen -= byte_cnt; *dst += byte_cnt; *offset += byte_cnt; } return 0; } STATIC void xfs_attr_rmtval_copyin( struct xfs_mount *mp, struct xfs_buf *bp, xfs_ino_t ino, int *offset, int *valuelen, __uint8_t **src) { char *dst = bp->b_addr; xfs_daddr_t bno = bp->b_bn; int len = BBTOB(bp->b_length); int blksize = mp->m_attr_geo->blksize; ASSERT(len >= blksize); while (len > 0 && *valuelen > 0) { int hdr_size; int byte_cnt = XFS_ATTR3_RMT_BUF_SPACE(mp, blksize); byte_cnt = min(*valuelen, byte_cnt); hdr_size = xfs_attr3_rmt_hdr_set(mp, dst, ino, *offset, byte_cnt, bno); memcpy(dst + hdr_size, *src, byte_cnt); /* * If this is the last block, zero the remainder of it. * Check that we are actually the last block, too. */ if (byte_cnt + hdr_size < blksize) { ASSERT(*valuelen - byte_cnt == 0); ASSERT(len == blksize); memset(dst + hdr_size + byte_cnt, 0, blksize - hdr_size - byte_cnt); } /* roll buffer forwards */ len -= blksize; dst += blksize; bno += BTOBB(blksize); /* roll attribute data forwards */ *valuelen -= byte_cnt; *src += byte_cnt; *offset += byte_cnt; } } /* * Read the value associated with an attribute from the out-of-line buffer * that we stored it in. */ int xfs_attr_rmtval_get( struct xfs_da_args *args) { struct xfs_bmbt_irec map[ATTR_RMTVALUE_MAPSIZE]; struct xfs_mount *mp = args->dp->i_mount; struct xfs_buf *bp; xfs_dablk_t lblkno = args->rmtblkno; __uint8_t *dst = args->value; int valuelen; int nmap; int error; int blkcnt = args->rmtblkcnt; int i; int offset = 0; trace_xfs_attr_rmtval_get(args); ASSERT(!(args->flags & ATTR_KERNOVAL)); ASSERT(args->rmtvaluelen == args->valuelen); valuelen = args->rmtvaluelen; while (valuelen > 0) { nmap = ATTR_RMTVALUE_MAPSIZE; error = xfs_bmapi_read(args->dp, (xfs_fileoff_t)lblkno, blkcnt, map, &nmap, XFS_BMAPI_ATTRFORK); if (error) return error; ASSERT(nmap >= 1); for (i = 0; (i < nmap) && (valuelen > 0); i++) { xfs_daddr_t dblkno; int dblkcnt; ASSERT((map[i].br_startblock != DELAYSTARTBLOCK) && (map[i].br_startblock != HOLESTARTBLOCK)); dblkno = XFS_FSB_TO_DADDR(mp, map[i].br_startblock); dblkcnt = XFS_FSB_TO_BB(mp, map[i].br_blockcount); error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp, dblkno, dblkcnt, 0, &bp, &xfs_attr3_rmt_buf_ops); if (error) return error; error = xfs_attr_rmtval_copyout(mp, bp, args->dp->i_ino, &offset, &valuelen, &dst); xfs_buf_relse(bp); if (error) return error; /* roll attribute extent map forwards */ lblkno += map[i].br_blockcount; blkcnt -= map[i].br_blockcount; } } ASSERT(valuelen == 0); return 0; } /* * Write the value associated with an attribute into the out-of-line buffer * that we have defined for it. */ int xfs_attr_rmtval_set( struct xfs_da_args *args) { struct xfs_inode *dp = args->dp; struct xfs_mount *mp = dp->i_mount; struct xfs_bmbt_irec map; xfs_dablk_t lblkno; xfs_fileoff_t lfileoff = 0; __uint8_t *src = args->value; int blkcnt; int valuelen; int nmap; int error; int offset = 0; trace_xfs_attr_rmtval_set(args); /* * Find a "hole" in the attribute address space large enough for * us to drop the new attribute's value into. Because CRC enable * attributes have headers, we can't just do a straight byte to FSB * conversion and have to take the header space into account. */ blkcnt = xfs_attr3_rmt_blocks(mp, args->rmtvaluelen); error = xfs_bmap_first_unused(args->trans, args->dp, blkcnt, &lfileoff, XFS_ATTR_FORK); if (error) return error; args->rmtblkno = lblkno = (xfs_dablk_t)lfileoff; args->rmtblkcnt = blkcnt; /* * Roll through the "value", allocating blocks on disk as required. */ while (blkcnt > 0) { int committed; /* * Allocate a single extent, up to the size of the value. * * Note that we have to consider this a data allocation as we * write the remote attribute without logging the contents. * Hence we must ensure that we aren't using blocks that are on * the busy list so that we don't overwrite blocks which have * recently been freed but their transactions are not yet * committed to disk. If we overwrite the contents of a busy * extent and then crash then the block may not contain the * correct metadata after log recovery occurs. */ xfs_bmap_init(args->flist, args->firstblock); nmap = 1; error = xfs_bmapi_write(args->trans, dp, (xfs_fileoff_t)lblkno, blkcnt, XFS_BMAPI_ATTRFORK, args->firstblock, args->total, &map, &nmap, args->flist); if (!error) { error = xfs_bmap_finish(&args->trans, args->flist, &committed); } if (error) { ASSERT(committed); args->trans = NULL; xfs_bmap_cancel(args->flist); return error; } /* * bmap_finish() may have committed the last trans and started * a new one. We need the inode to be in all transactions. */ if (committed) xfs_trans_ijoin(args->trans, dp, 0); ASSERT(nmap == 1); ASSERT((map.br_startblock != DELAYSTARTBLOCK) && (map.br_startblock != HOLESTARTBLOCK)); lblkno += map.br_blockcount; blkcnt -= map.br_blockcount; /* * Start the next trans in the chain. */ error = xfs_trans_roll(&args->trans, dp); if (error) return error; } /* * Roll through the "value", copying the attribute value to the * already-allocated blocks. Blocks are written synchronously * so that we can know they are all on disk before we turn off * the INCOMPLETE flag. */ lblkno = args->rmtblkno; blkcnt = args->rmtblkcnt; valuelen = args->rmtvaluelen; while (valuelen > 0) { struct xfs_buf *bp; xfs_daddr_t dblkno; int dblkcnt; ASSERT(blkcnt > 0); xfs_bmap_init(args->flist, args->firstblock); nmap = 1; error = xfs_bmapi_read(dp, (xfs_fileoff_t)lblkno, blkcnt, &map, &nmap, XFS_BMAPI_ATTRFORK); if (error) return error; ASSERT(nmap == 1); ASSERT((map.br_startblock != DELAYSTARTBLOCK) && (map.br_startblock != HOLESTARTBLOCK)); dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock), dblkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount); bp = xfs_buf_get(mp->m_ddev_targp, dblkno, dblkcnt, 0); if (!bp) return -ENOMEM; bp->b_ops = &xfs_attr3_rmt_buf_ops; xfs_attr_rmtval_copyin(mp, bp, args->dp->i_ino, &offset, &valuelen, &src); error = xfs_bwrite(bp); /* GROT: NOTE: synchronous write */ xfs_buf_relse(bp); if (error) return error; /* roll attribute extent map forwards */ lblkno += map.br_blockcount; blkcnt -= map.br_blockcount; } ASSERT(valuelen == 0); return 0; } /* * Remove the value associated with an attribute by deleting the * out-of-line buffer that it is stored on. */ int xfs_attr_rmtval_remove( struct xfs_da_args *args) { struct xfs_mount *mp = args->dp->i_mount; xfs_dablk_t lblkno; int blkcnt; int error; int done; trace_xfs_attr_rmtval_remove(args); /* * Roll through the "value", invalidating the attribute value's blocks. */ lblkno = args->rmtblkno; blkcnt = args->rmtblkcnt; while (blkcnt > 0) { struct xfs_bmbt_irec map; struct xfs_buf *bp; xfs_daddr_t dblkno; int dblkcnt; int nmap; /* * Try to remember where we decided to put the value. */ nmap = 1; error = xfs_bmapi_read(args->dp, (xfs_fileoff_t)lblkno, blkcnt, &map, &nmap, XFS_BMAPI_ATTRFORK); if (error) return error; ASSERT(nmap == 1); ASSERT((map.br_startblock != DELAYSTARTBLOCK) && (map.br_startblock != HOLESTARTBLOCK)); dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock), dblkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount); /* * If the "remote" value is in the cache, remove it. */ bp = xfs_incore(mp->m_ddev_targp, dblkno, dblkcnt, XBF_TRYLOCK); if (bp) { xfs_buf_stale(bp); xfs_buf_relse(bp); bp = NULL; } lblkno += map.br_blockcount; blkcnt -= map.br_blockcount; } /* * Keep de-allocating extents until the remote-value region is gone. */ lblkno = args->rmtblkno; blkcnt = args->rmtblkcnt; done = 0; while (!done) { int committed; xfs_bmap_init(args->flist, args->firstblock); error = xfs_bunmapi(args->trans, args->dp, lblkno, blkcnt, XFS_BMAPI_ATTRFORK, 1, args->firstblock, args->flist, &done); if (!error) { error = xfs_bmap_finish(&args->trans, args->flist, &committed); } if (error) { ASSERT(committed); args->trans = NULL; xfs_bmap_cancel(args->flist); return error; } /* * bmap_finish() may have committed the last trans and started * a new one. We need the inode to be in all transactions. */ if (committed) xfs_trans_ijoin(args->trans, args->dp, 0); /* * Close out trans and start the next one in the chain. */ error = xfs_trans_roll(&args->trans, args->dp); if (error) return error; } return 0; } partclone-0.2.86/src/xfs/xfs_attr_remote.h000066400000000000000000000017771262102574200205600ustar00rootroot00000000000000/* * Copyright (c) 2013 Red Hat, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __XFS_ATTR_REMOTE_H__ #define __XFS_ATTR_REMOTE_H__ int xfs_attr3_rmt_blocks(struct xfs_mount *mp, int attrlen); int xfs_attr_rmtval_get(struct xfs_da_args *args); int xfs_attr_rmtval_set(struct xfs_da_args *args); int xfs_attr_rmtval_remove(struct xfs_da_args *args); #endif /* __XFS_ATTR_REMOTE_H__ */ partclone-0.2.86/src/xfs/xfs_attr_sf.h000066400000000000000000000054161262102574200176670ustar00rootroot00000000000000/* * Copyright (c) 2000,2002,2005 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __XFS_ATTR_SF_H__ #define __XFS_ATTR_SF_H__ /* * Attribute storage when stored inside the inode. * * Small attribute lists are packed as tightly as possible so as * to fit into the literal area of the inode. */ /* * Entries are packed toward the top as tight as possible. */ typedef struct xfs_attr_shortform { struct xfs_attr_sf_hdr { /* constant-structure header block */ __be16 totsize; /* total bytes in shortform list */ __u8 count; /* count of active entries */ } hdr; struct xfs_attr_sf_entry { __uint8_t namelen; /* actual length of name (no NULL) */ __uint8_t valuelen; /* actual length of value (no NULL) */ __uint8_t flags; /* flags bits (see xfs_attr_leaf.h) */ __uint8_t nameval[1]; /* name & value bytes concatenated */ } list[1]; /* variable sized array */ } xfs_attr_shortform_t; typedef struct xfs_attr_sf_hdr xfs_attr_sf_hdr_t; typedef struct xfs_attr_sf_entry xfs_attr_sf_entry_t; /* * We generate this then sort it, attr_list() must return things in hash-order. */ typedef struct xfs_attr_sf_sort { __uint8_t entno; /* entry number in original list */ __uint8_t namelen; /* length of name value (no null) */ __uint8_t valuelen; /* length of value */ __uint8_t flags; /* flags bits (see xfs_attr_leaf.h) */ xfs_dahash_t hash; /* this entry's hash value */ unsigned char *name; /* name value, pointer into buffer */ } xfs_attr_sf_sort_t; #define XFS_ATTR_SF_ENTSIZE_BYNAME(nlen,vlen) /* space name/value uses */ \ (((int)sizeof(xfs_attr_sf_entry_t)-1 + (nlen)+(vlen))) #define XFS_ATTR_SF_ENTSIZE_MAX /* max space for name&value */ \ ((1 << (NBBY*(int)sizeof(__uint8_t))) - 1) #define XFS_ATTR_SF_ENTSIZE(sfep) /* space an entry uses */ \ ((int)sizeof(xfs_attr_sf_entry_t)-1 + (sfep)->namelen+(sfep)->valuelen) #define XFS_ATTR_SF_NEXTENTRY(sfep) /* next entry in struct */ \ ((xfs_attr_sf_entry_t *)((char *)(sfep) + XFS_ATTR_SF_ENTSIZE(sfep))) #define XFS_ATTR_SF_TOTSIZE(dp) /* total space in use */ \ (be16_to_cpu(((xfs_attr_shortform_t *) \ ((dp)->i_afp->if_u1.if_data))->hdr.totsize)) #endif /* __XFS_ATTR_SF_H__ */ partclone-0.2.86/src/xfs/xfs_bit.c000066400000000000000000000054471262102574200170020ustar00rootroot00000000000000/* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "libxfs_priv.h" #include "xfs_log_format.h" #include "xfs_bit.h" /* * XFS bit manipulation routines, used in non-realtime code. */ /* * Return whether bitmap is empty. * Size is number of words in the bitmap, which is padded to word boundary * Returns 1 for empty, 0 for non-empty. */ int xfs_bitmap_empty(uint *map, uint size) { uint i; uint ret = 0; for (i = 0; i < size; i++) { ret |= map[i]; } return (ret == 0); } /* * Count the number of contiguous bits set in the bitmap starting with bit * start_bit. Size is the size of the bitmap in words. */ int xfs_contig_bits(uint *map, uint size, uint start_bit) { uint * p = ((unsigned int *) map) + (start_bit >> BIT_TO_WORD_SHIFT); uint result = 0; uint tmp; size <<= BIT_TO_WORD_SHIFT; ASSERT(start_bit < size); size -= start_bit & ~(NBWORD - 1); start_bit &= (NBWORD - 1); if (start_bit) { tmp = *p++; /* set to one first offset bits prior to start */ tmp |= (~0U >> (NBWORD-start_bit)); if (tmp != ~0U) goto found; result += NBWORD; size -= NBWORD; } while (size) { if ((tmp = *p++) != ~0U) goto found; result += NBWORD; size -= NBWORD; } return result - start_bit; found: return result + ffz(tmp) - start_bit; } /* * This takes the bit number to start looking from and * returns the next set bit from there. It returns -1 * if there are no more bits set or the start bit is * beyond the end of the bitmap. * * Size is the number of words, not bytes, in the bitmap. */ int xfs_next_bit(uint *map, uint size, uint start_bit) { uint * p = ((unsigned int *) map) + (start_bit >> BIT_TO_WORD_SHIFT); uint result = start_bit & ~(NBWORD - 1); uint tmp; size <<= BIT_TO_WORD_SHIFT; if (start_bit >= size) return -1; size -= result; start_bit &= (NBWORD - 1); if (start_bit) { tmp = *p++; /* set to zero first offset bits prior to start */ tmp &= (~0U << start_bit); if (tmp != 0U) goto found; result += NBWORD; size -= NBWORD; } while (size) { if ((tmp = *p++) != 0U) goto found; result += NBWORD; size -= NBWORD; } return -1; found: return result + ffs(tmp) - 1; } partclone-0.2.86/src/xfs/xfs_bit.h000066400000000000000000000042351262102574200170010ustar00rootroot00000000000000/* * Copyright (c) 2000,2002,2005 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __XFS_BIT_H__ #define __XFS_BIT_H__ /* * XFS bit manipulation routines. */ /* * masks with n high/low bits set, 64-bit values */ static inline __uint64_t xfs_mask64hi(int n) { return (__uint64_t)-1 << (64 - (n)); } static inline __uint32_t xfs_mask32lo(int n) { return ((__uint32_t)1 << (n)) - 1; } static inline __uint64_t xfs_mask64lo(int n) { return ((__uint64_t)1 << (n)) - 1; } /* Get high bit set out of 32-bit argument, -1 if none set */ static inline int xfs_highbit32(__uint32_t v) { return fls(v) - 1; } /* Get high bit set out of 64-bit argument, -1 if none set */ static inline int xfs_highbit64(__uint64_t v) { return fls64(v) - 1; } /* Get low bit set out of 32-bit argument, -1 if none set */ static inline int xfs_lowbit32(__uint32_t v) { return ffs(v) - 1; } /* Get low bit set out of 64-bit argument, -1 if none set */ static inline int xfs_lowbit64(__uint64_t v) { __uint32_t w = (__uint32_t)v; int n = 0; if (w) { /* lower bits */ n = ffs(w); } else { /* upper bits */ w = (__uint32_t)(v >> 32); if (w) { n = ffs(w); if (n) n += 32; } } return n - 1; } /* Return whether bitmap is empty (1 == empty) */ extern int xfs_bitmap_empty(uint *map, uint size); /* Count continuous one bits in map starting with start_bit */ extern int xfs_contig_bits(uint *map, uint size, uint start_bit); /* Find next set bit in map */ extern int xfs_next_bit(uint *map, uint size, uint start_bit); #endif /* __XFS_BIT_H__ */ partclone-0.2.86/src/xfs/xfs_bmap.c000066400000000000000000005236011262102574200171400ustar00rootroot00000000000000/* * Copyright (c) 2000-2006 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_bit.h" #include "xfs_sb.h" #include "xfs_mount.h" #include "xfs_da_format.h" #include "xfs_da_btree.h" #include "xfs_dir2.h" #include "xfs_inode.h" #include "xfs_btree.h" #include "xfs_trans.h" #include "xfs_alloc.h" #include "xfs_bmap.h" #include "xfs_bmap_btree.h" #include "xfs_trans_space.h" #include "xfs_trace.h" #include "xfs_attr_leaf.h" #include "xfs_quota_defs.h" kmem_zone_t *xfs_bmap_free_item_zone; /* * Miscellaneous helper functions */ /* * Compute and fill in the value of the maximum depth of a bmap btree * in this filesystem. Done once, during mount. */ void xfs_bmap_compute_maxlevels( xfs_mount_t *mp, /* file system mount structure */ int whichfork) /* data or attr fork */ { int level; /* btree level */ uint maxblocks; /* max blocks at this level */ uint maxleafents; /* max leaf entries possible */ int maxrootrecs; /* max records in root block */ int minleafrecs; /* min records in leaf block */ int minnoderecs; /* min records in node block */ int sz; /* root block size */ /* * The maximum number of extents in a file, hence the maximum * number of leaf entries, is controlled by the type of di_nextents * (a signed 32-bit number, xfs_extnum_t), or by di_anextents * (a signed 16-bit number, xfs_aextnum_t). * * Note that we can no longer assume that if we are in ATTR1 that * the fork offset of all the inodes will be * (xfs_default_attroffset(ip) >> 3) because we could have mounted * with ATTR2 and then mounted back with ATTR1, keeping the * di_forkoff's fixed but probably at various positions. Therefore, * for both ATTR1 and ATTR2 we have to assume the worst case scenario * of a minimum size available. */ if (whichfork == XFS_DATA_FORK) { maxleafents = MAXEXTNUM; sz = XFS_BMDR_SPACE_CALC(MINDBTPTRS); } else { maxleafents = MAXAEXTNUM; sz = XFS_BMDR_SPACE_CALC(MINABTPTRS); } maxrootrecs = xfs_bmdr_maxrecs(sz, 0); minleafrecs = mp->m_bmap_dmnr[0]; minnoderecs = mp->m_bmap_dmnr[1]; maxblocks = (maxleafents + minleafrecs - 1) / minleafrecs; for (level = 1; maxblocks > 1; level++) { if (maxblocks <= maxrootrecs) maxblocks = 1; else maxblocks = (maxblocks + minnoderecs - 1) / minnoderecs; } mp->m_bm_maxlevels[whichfork] = level; } STATIC int /* error */ xfs_bmbt_lookup_eq( struct xfs_btree_cur *cur, xfs_fileoff_t off, xfs_fsblock_t bno, xfs_filblks_t len, int *stat) /* success/failure */ { cur->bc_rec.b.br_startoff = off; cur->bc_rec.b.br_startblock = bno; cur->bc_rec.b.br_blockcount = len; return xfs_btree_lookup(cur, XFS_LOOKUP_EQ, stat); } STATIC int /* error */ xfs_bmbt_lookup_ge( struct xfs_btree_cur *cur, xfs_fileoff_t off, xfs_fsblock_t bno, xfs_filblks_t len, int *stat) /* success/failure */ { cur->bc_rec.b.br_startoff = off; cur->bc_rec.b.br_startblock = bno; cur->bc_rec.b.br_blockcount = len; return xfs_btree_lookup(cur, XFS_LOOKUP_GE, stat); } /* * Check if the inode needs to be converted to btree format. */ static inline bool xfs_bmap_needs_btree(struct xfs_inode *ip, int whichfork) { return XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_EXTENTS && XFS_IFORK_NEXTENTS(ip, whichfork) > XFS_IFORK_MAXEXT(ip, whichfork); } /* * Check if the inode should be converted to extent format. */ static inline bool xfs_bmap_wants_extents(struct xfs_inode *ip, int whichfork) { return XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE && XFS_IFORK_NEXTENTS(ip, whichfork) <= XFS_IFORK_MAXEXT(ip, whichfork); } /* * Update the record referred to by cur to the value given * by [off, bno, len, state]. * This either works (return 0) or gets an EFSCORRUPTED error. */ STATIC int xfs_bmbt_update( struct xfs_btree_cur *cur, xfs_fileoff_t off, xfs_fsblock_t bno, xfs_filblks_t len, xfs_exntst_t state) { union xfs_btree_rec rec; xfs_bmbt_disk_set_allf(&rec.bmbt, off, bno, len, state); return xfs_btree_update(cur, &rec); } /* * Compute the worst-case number of indirect blocks that will be used * for ip's delayed extent of length "len". */ STATIC xfs_filblks_t xfs_bmap_worst_indlen( xfs_inode_t *ip, /* incore inode pointer */ xfs_filblks_t len) /* delayed extent length */ { int level; /* btree level number */ int maxrecs; /* maximum record count at this level */ xfs_mount_t *mp; /* mount structure */ xfs_filblks_t rval; /* return value */ mp = ip->i_mount; maxrecs = mp->m_bmap_dmxr[0]; for (level = 0, rval = 0; level < XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK); level++) { len += maxrecs - 1; do_div(len, maxrecs); rval += len; if (len == 1) return rval + XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) - level - 1; if (level == 0) maxrecs = mp->m_bmap_dmxr[1]; } return rval; } /* * Calculate the default attribute fork offset for newly created inodes. */ uint xfs_default_attroffset( struct xfs_inode *ip) { struct xfs_mount *mp = ip->i_mount; uint offset; if (mp->m_sb.sb_inodesize == 256) { offset = XFS_LITINO(mp, ip->i_d.di_version) - XFS_BMDR_SPACE_CALC(MINABTPTRS); } else { offset = XFS_BMDR_SPACE_CALC(6 * MINABTPTRS); } ASSERT(offset < XFS_LITINO(mp, ip->i_d.di_version)); return offset; } /* * Helper routine to reset inode di_forkoff field when switching * attribute fork from local to extent format - we reset it where * possible to make space available for inline data fork extents. */ STATIC void xfs_bmap_forkoff_reset( xfs_inode_t *ip, int whichfork) { if (whichfork == XFS_ATTR_FORK && ip->i_d.di_format != XFS_DINODE_FMT_DEV && ip->i_d.di_format != XFS_DINODE_FMT_UUID && ip->i_d.di_format != XFS_DINODE_FMT_BTREE) { uint dfl_forkoff = xfs_default_attroffset(ip) >> 3; if (dfl_forkoff > ip->i_d.di_forkoff) ip->i_d.di_forkoff = dfl_forkoff; } } #ifdef DEBUG STATIC struct xfs_buf * xfs_bmap_get_bp( struct xfs_btree_cur *cur, xfs_fsblock_t bno) { struct xfs_log_item_desc *lidp; int i; if (!cur) return NULL; for (i = 0; i < XFS_BTREE_MAXLEVELS; i++) { if (!cur->bc_bufs[i]) break; if (XFS_BUF_ADDR(cur->bc_bufs[i]) == bno) return cur->bc_bufs[i]; } /* Chase down all the log items to see if the bp is there */ list_for_each_entry(lidp, &cur->bc_tp->t_items, lid_trans) { struct xfs_buf_log_item *bip; bip = (struct xfs_buf_log_item *)lidp->lid_item; if (bip->bli_item.li_type == XFS_LI_BUF && XFS_BUF_ADDR(bip->bli_buf) == bno) return bip->bli_buf; } return NULL; } STATIC void xfs_check_block( struct xfs_btree_block *block, xfs_mount_t *mp, int root, short sz) { int i, j, dmxr; __be64 *pp, *thispa; /* pointer to block address */ xfs_bmbt_key_t *prevp, *keyp; ASSERT(be16_to_cpu(block->bb_level) > 0); prevp = NULL; for( i = 1; i <= xfs_btree_get_numrecs(block); i++) { dmxr = mp->m_bmap_dmxr[0]; keyp = XFS_BMBT_KEY_ADDR(mp, block, i); if (prevp) { ASSERT(be64_to_cpu(prevp->br_startoff) < be64_to_cpu(keyp->br_startoff)); } prevp = keyp; /* * Compare the block numbers to see if there are dups. */ if (root) pp = XFS_BMAP_BROOT_PTR_ADDR(mp, block, i, sz); else pp = XFS_BMBT_PTR_ADDR(mp, block, i, dmxr); for (j = i+1; j <= be16_to_cpu(block->bb_numrecs); j++) { if (root) thispa = XFS_BMAP_BROOT_PTR_ADDR(mp, block, j, sz); else thispa = XFS_BMBT_PTR_ADDR(mp, block, j, dmxr); if (*thispa == *pp) { xfs_warn(mp, "%s: thispa(%d) == pp(%d) %Ld", __func__, j, i, (unsigned long long)be64_to_cpu(*thispa)); panic("%s: ptrs are equal in node\n", __func__); } } } } /* * Check that the extents for the inode ip are in the right order in all * btree leaves. */ STATIC void xfs_bmap_check_leaf_extents( xfs_btree_cur_t *cur, /* btree cursor or null */ xfs_inode_t *ip, /* incore inode pointer */ int whichfork) /* data or attr fork */ { struct xfs_btree_block *block; /* current btree block */ xfs_fsblock_t bno; /* block # of "block" */ xfs_buf_t *bp; /* buffer for "block" */ int error; /* error return value */ xfs_extnum_t i=0, j; /* index into the extents list */ xfs_ifork_t *ifp; /* fork structure */ int level; /* btree level, for checking */ xfs_mount_t *mp; /* file system mount structure */ __be64 *pp; /* pointer to block address */ xfs_bmbt_rec_t *ep; /* pointer to current extent */ xfs_bmbt_rec_t last = {0, 0}; /* last extent in prev block */ xfs_bmbt_rec_t *nextp; /* pointer to next extent */ int bp_release = 0; if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE) { return; } bno = NULLFSBLOCK; mp = ip->i_mount; ifp = XFS_IFORK_PTR(ip, whichfork); block = ifp->if_broot; /* * Root level must use BMAP_BROOT_PTR_ADDR macro to get ptr out. */ level = be16_to_cpu(block->bb_level); ASSERT(level > 0); xfs_check_block(block, mp, 1, ifp->if_broot_bytes); pp = XFS_BMAP_BROOT_PTR_ADDR(mp, block, 1, ifp->if_broot_bytes); bno = be64_to_cpu(*pp); ASSERT(bno != NULLFSBLOCK); ASSERT(XFS_FSB_TO_AGNO(mp, bno) < mp->m_sb.sb_agcount); ASSERT(XFS_FSB_TO_AGBNO(mp, bno) < mp->m_sb.sb_agblocks); /* * Go down the tree until leaf level is reached, following the first * pointer (leftmost) at each level. */ while (level-- > 0) { /* See if buf is in cur first */ bp_release = 0; bp = xfs_bmap_get_bp(cur, XFS_FSB_TO_DADDR(mp, bno)); if (!bp) { bp_release = 1; error = xfs_btree_read_bufl(mp, NULL, bno, 0, &bp, XFS_BMAP_BTREE_REF, &xfs_bmbt_buf_ops); if (error) goto error_norelse; } block = XFS_BUF_TO_BLOCK(bp); if (level == 0) break; /* * Check this block for basic sanity (increasing keys and * no duplicate blocks). */ xfs_check_block(block, mp, 0, 0); pp = XFS_BMBT_PTR_ADDR(mp, block, 1, mp->m_bmap_dmxr[1]); bno = be64_to_cpu(*pp); XFS_WANT_CORRUPTED_GOTO(mp, XFS_FSB_SANITY_CHECK(mp, bno), error0); if (bp_release) { bp_release = 0; xfs_trans_brelse(NULL, bp); } } /* * Here with bp and block set to the leftmost leaf node in the tree. */ i = 0; /* * Loop over all leaf nodes checking that all extents are in the right order. */ for (;;) { xfs_fsblock_t nextbno; xfs_extnum_t num_recs; num_recs = xfs_btree_get_numrecs(block); /* * Read-ahead the next leaf block, if any. */ nextbno = be64_to_cpu(block->bb_u.l.bb_rightsib); /* * Check all the extents to make sure they are OK. * If we had a previous block, the last entry should * conform with the first entry in this one. */ ep = XFS_BMBT_REC_ADDR(mp, block, 1); if (i) { ASSERT(xfs_bmbt_disk_get_startoff(&last) + xfs_bmbt_disk_get_blockcount(&last) <= xfs_bmbt_disk_get_startoff(ep)); } for (j = 1; j < num_recs; j++) { nextp = XFS_BMBT_REC_ADDR(mp, block, j + 1); ASSERT(xfs_bmbt_disk_get_startoff(ep) + xfs_bmbt_disk_get_blockcount(ep) <= xfs_bmbt_disk_get_startoff(nextp)); ep = nextp; } last = *ep; i += num_recs; if (bp_release) { bp_release = 0; xfs_trans_brelse(NULL, bp); } bno = nextbno; /* * If we've reached the end, stop. */ if (bno == NULLFSBLOCK) break; bp_release = 0; bp = xfs_bmap_get_bp(cur, XFS_FSB_TO_DADDR(mp, bno)); if (!bp) { bp_release = 1; error = xfs_btree_read_bufl(mp, NULL, bno, 0, &bp, XFS_BMAP_BTREE_REF, &xfs_bmbt_buf_ops); if (error) goto error_norelse; } block = XFS_BUF_TO_BLOCK(bp); } if (bp_release) { bp_release = 0; xfs_trans_brelse(NULL, bp); } return; error0: xfs_warn(mp, "%s: at error0", __func__); if (bp_release) xfs_trans_brelse(NULL, bp); error_norelse: xfs_warn(mp, "%s: BAD after btree leaves for %d extents", __func__, i); panic("%s: CORRUPTED BTREE OR SOMETHING", __func__); return; } /* * Add bmap trace insert entries for all the contents of the extent records. */ void xfs_bmap_trace_exlist( xfs_inode_t *ip, /* incore inode pointer */ xfs_extnum_t cnt, /* count of entries in the list */ int whichfork, /* data or attr fork */ unsigned long caller_ip) { xfs_extnum_t idx; /* extent record index */ xfs_ifork_t *ifp; /* inode fork pointer */ int state = 0; if (whichfork == XFS_ATTR_FORK) state |= BMAP_ATTRFORK; ifp = XFS_IFORK_PTR(ip, whichfork); ASSERT(cnt == (ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t))); for (idx = 0; idx < cnt; idx++) trace_xfs_extlist(ip, idx, whichfork, caller_ip); } /* * Validate that the bmbt_irecs being returned from bmapi are valid * given the caller's original parameters. Specifically check the * ranges of the returned irecs to ensure that they only extend beyond * the given parameters if the XFS_BMAPI_ENTIRE flag was set. */ STATIC void xfs_bmap_validate_ret( xfs_fileoff_t bno, xfs_filblks_t len, int flags, xfs_bmbt_irec_t *mval, int nmap, int ret_nmap) { int i; /* index to map values */ ASSERT(ret_nmap <= nmap); for (i = 0; i < ret_nmap; i++) { ASSERT(mval[i].br_blockcount > 0); if (!(flags & XFS_BMAPI_ENTIRE)) { ASSERT(mval[i].br_startoff >= bno); ASSERT(mval[i].br_blockcount <= len); ASSERT(mval[i].br_startoff + mval[i].br_blockcount <= bno + len); } else { ASSERT(mval[i].br_startoff < bno + len); ASSERT(mval[i].br_startoff + mval[i].br_blockcount > bno); } ASSERT(i == 0 || mval[i - 1].br_startoff + mval[i - 1].br_blockcount == mval[i].br_startoff); ASSERT(mval[i].br_startblock != DELAYSTARTBLOCK && mval[i].br_startblock != HOLESTARTBLOCK); ASSERT(mval[i].br_state == XFS_EXT_NORM || mval[i].br_state == XFS_EXT_UNWRITTEN); } } #else #define xfs_bmap_check_leaf_extents(cur, ip, whichfork) do { } while (0) #define xfs_bmap_validate_ret(bno,len,flags,mval,onmap,nmap) #endif /* DEBUG */ /* * bmap free list manipulation functions */ /* * Add the extent to the list of extents to be free at transaction end. * The list is maintained sorted (by block number). */ void xfs_bmap_add_free( xfs_fsblock_t bno, /* fs block number of extent */ xfs_filblks_t len, /* length of extent */ xfs_bmap_free_t *flist, /* list of extents */ xfs_mount_t *mp) /* mount point structure */ { xfs_bmap_free_item_t *cur; /* current (next) element */ xfs_bmap_free_item_t *new; /* new element */ xfs_bmap_free_item_t *prev; /* previous element */ #ifdef DEBUG xfs_agnumber_t agno; xfs_agblock_t agbno; ASSERT(bno != NULLFSBLOCK); ASSERT(len > 0); ASSERT(len <= MAXEXTLEN); ASSERT(!isnullstartblock(bno)); agno = XFS_FSB_TO_AGNO(mp, bno); agbno = XFS_FSB_TO_AGBNO(mp, bno); ASSERT(agno < mp->m_sb.sb_agcount); ASSERT(agbno < mp->m_sb.sb_agblocks); ASSERT(len < mp->m_sb.sb_agblocks); ASSERT(agbno + len <= mp->m_sb.sb_agblocks); #endif ASSERT(xfs_bmap_free_item_zone != NULL); new = kmem_zone_alloc(xfs_bmap_free_item_zone, KM_SLEEP); new->xbfi_startblock = bno; new->xbfi_blockcount = (xfs_extlen_t)len; for (prev = NULL, cur = flist->xbf_first; cur != NULL; prev = cur, cur = cur->xbfi_next) { if (cur->xbfi_startblock >= bno) break; } if (prev) prev->xbfi_next = new; else flist->xbf_first = new; new->xbfi_next = cur; flist->xbf_count++; } /* * Remove the entry "free" from the free item list. Prev points to the * previous entry, unless "free" is the head of the list. */ void xfs_bmap_del_free( xfs_bmap_free_t *flist, /* free item list header */ xfs_bmap_free_item_t *prev, /* previous item on list, if any */ xfs_bmap_free_item_t *free) /* list item to be freed */ { if (prev) prev->xbfi_next = free->xbfi_next; else flist->xbf_first = free->xbfi_next; flist->xbf_count--; kmem_zone_free(xfs_bmap_free_item_zone, free); } /* * Free up any items left in the list. */ void xfs_bmap_cancel( xfs_bmap_free_t *flist) /* list of bmap_free_items */ { xfs_bmap_free_item_t *free; /* free list item */ xfs_bmap_free_item_t *next; if (flist->xbf_count == 0) return; ASSERT(flist->xbf_first != NULL); for (free = flist->xbf_first; free; free = next) { next = free->xbfi_next; xfs_bmap_del_free(flist, NULL, free); } ASSERT(flist->xbf_count == 0); } /* * Inode fork format manipulation functions */ /* * Transform a btree format file with only one leaf node, where the * extents list will fit in the inode, into an extents format file. * Since the file extents are already in-core, all we have to do is * give up the space for the btree root and pitch the leaf block. */ STATIC int /* error */ xfs_bmap_btree_to_extents( xfs_trans_t *tp, /* transaction pointer */ xfs_inode_t *ip, /* incore inode pointer */ xfs_btree_cur_t *cur, /* btree cursor */ int *logflagsp, /* inode logging flags */ int whichfork) /* data or attr fork */ { /* REFERENCED */ struct xfs_btree_block *cblock;/* child btree block */ xfs_fsblock_t cbno; /* child block number */ xfs_buf_t *cbp; /* child block's buffer */ int error; /* error return value */ xfs_ifork_t *ifp; /* inode fork data */ xfs_mount_t *mp; /* mount point structure */ __be64 *pp; /* ptr to block address */ struct xfs_btree_block *rblock;/* root btree block */ mp = ip->i_mount; ifp = XFS_IFORK_PTR(ip, whichfork); ASSERT(ifp->if_flags & XFS_IFEXTENTS); ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE); rblock = ifp->if_broot; ASSERT(be16_to_cpu(rblock->bb_level) == 1); ASSERT(be16_to_cpu(rblock->bb_numrecs) == 1); ASSERT(xfs_bmbt_maxrecs(mp, ifp->if_broot_bytes, 0) == 1); pp = XFS_BMAP_BROOT_PTR_ADDR(mp, rblock, 1, ifp->if_broot_bytes); cbno = be64_to_cpu(*pp); *logflagsp = 0; #ifdef DEBUG if ((error = xfs_btree_check_lptr(cur, cbno, 1))) return error; #endif error = xfs_btree_read_bufl(mp, tp, cbno, 0, &cbp, XFS_BMAP_BTREE_REF, &xfs_bmbt_buf_ops); if (error) return error; cblock = XFS_BUF_TO_BLOCK(cbp); if ((error = xfs_btree_check_block(cur, cblock, 0, cbp))) return error; xfs_bmap_add_free(cbno, 1, cur->bc_private.b.flist, mp); ip->i_d.di_nblocks--; xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_BCOUNT, -1L); xfs_trans_binval(tp, cbp); if (cur->bc_bufs[0] == cbp) cur->bc_bufs[0] = NULL; xfs_iroot_realloc(ip, -1, whichfork); ASSERT(ifp->if_broot == NULL); ASSERT((ifp->if_flags & XFS_IFBROOT) == 0); XFS_IFORK_FMT_SET(ip, whichfork, XFS_DINODE_FMT_EXTENTS); *logflagsp = XFS_ILOG_CORE | xfs_ilog_fext(whichfork); return 0; } /* * Convert an extents-format file into a btree-format file. * The new file will have a root block (in the inode) and a single child block. */ STATIC int /* error */ xfs_bmap_extents_to_btree( xfs_trans_t *tp, /* transaction pointer */ xfs_inode_t *ip, /* incore inode pointer */ xfs_fsblock_t *firstblock, /* first-block-allocated */ xfs_bmap_free_t *flist, /* blocks freed in xaction */ xfs_btree_cur_t **curp, /* cursor returned to caller */ int wasdel, /* converting a delayed alloc */ int *logflagsp, /* inode logging flags */ int whichfork) /* data or attr fork */ { struct xfs_btree_block *ablock; /* allocated (child) bt block */ xfs_buf_t *abp; /* buffer for ablock */ xfs_alloc_arg_t args; /* allocation arguments */ xfs_bmbt_rec_t *arp; /* child record pointer */ struct xfs_btree_block *block; /* btree root block */ xfs_btree_cur_t *cur; /* bmap btree cursor */ xfs_bmbt_rec_host_t *ep; /* extent record pointer */ int error; /* error return value */ xfs_extnum_t i, cnt; /* extent record index */ xfs_ifork_t *ifp; /* inode fork pointer */ xfs_bmbt_key_t *kp; /* root block key pointer */ xfs_mount_t *mp; /* mount structure */ xfs_extnum_t nextents; /* number of file extents */ xfs_bmbt_ptr_t *pp; /* root block address pointer */ mp = ip->i_mount; ifp = XFS_IFORK_PTR(ip, whichfork); ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_EXTENTS); /* * Make space in the inode incore. */ xfs_iroot_realloc(ip, 1, whichfork); ifp->if_flags |= XFS_IFBROOT; /* * Fill in the root. */ block = ifp->if_broot; if (xfs_sb_version_hascrc(&mp->m_sb)) xfs_btree_init_block_int(mp, block, XFS_BUF_DADDR_NULL, XFS_BMAP_CRC_MAGIC, 1, 1, ip->i_ino, XFS_BTREE_LONG_PTRS | XFS_BTREE_CRC_BLOCKS); else xfs_btree_init_block_int(mp, block, XFS_BUF_DADDR_NULL, XFS_BMAP_MAGIC, 1, 1, ip->i_ino, XFS_BTREE_LONG_PTRS); /* * Need a cursor. Can't allocate until bb_level is filled in. */ cur = xfs_bmbt_init_cursor(mp, tp, ip, whichfork); cur->bc_private.b.firstblock = *firstblock; cur->bc_private.b.flist = flist; cur->bc_private.b.flags = wasdel ? XFS_BTCUR_BPRV_WASDEL : 0; /* * Convert to a btree with two levels, one record in root. */ XFS_IFORK_FMT_SET(ip, whichfork, XFS_DINODE_FMT_BTREE); memset(&args, 0, sizeof(args)); args.tp = tp; args.mp = mp; args.firstblock = *firstblock; if (*firstblock == NULLFSBLOCK) { args.type = XFS_ALLOCTYPE_START_BNO; args.fsbno = XFS_INO_TO_FSB(mp, ip->i_ino); } else if (flist->xbf_low) { args.type = XFS_ALLOCTYPE_START_BNO; args.fsbno = *firstblock; } else { args.type = XFS_ALLOCTYPE_NEAR_BNO; args.fsbno = *firstblock; } args.minlen = args.maxlen = args.prod = 1; args.wasdel = wasdel; *logflagsp = 0; if ((error = xfs_alloc_vextent(&args))) { xfs_iroot_realloc(ip, -1, whichfork); xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); return error; } /* * Allocation can't fail, the space was reserved. */ ASSERT(args.fsbno != NULLFSBLOCK); ASSERT(*firstblock == NULLFSBLOCK || args.agno == XFS_FSB_TO_AGNO(mp, *firstblock) || (flist->xbf_low && args.agno > XFS_FSB_TO_AGNO(mp, *firstblock))); *firstblock = cur->bc_private.b.firstblock = args.fsbno; cur->bc_private.b.allocated++; ip->i_d.di_nblocks++; xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_BCOUNT, 1L); abp = xfs_btree_get_bufl(mp, tp, args.fsbno, 0); /* * Fill in the child block. */ abp->b_ops = &xfs_bmbt_buf_ops; ablock = XFS_BUF_TO_BLOCK(abp); if (xfs_sb_version_hascrc(&mp->m_sb)) xfs_btree_init_block_int(mp, ablock, abp->b_bn, XFS_BMAP_CRC_MAGIC, 0, 0, ip->i_ino, XFS_BTREE_LONG_PTRS | XFS_BTREE_CRC_BLOCKS); else xfs_btree_init_block_int(mp, ablock, abp->b_bn, XFS_BMAP_MAGIC, 0, 0, ip->i_ino, XFS_BTREE_LONG_PTRS); arp = XFS_BMBT_REC_ADDR(mp, ablock, 1); nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); for (cnt = i = 0; i < nextents; i++) { ep = xfs_iext_get_ext(ifp, i); if (!isnullstartblock(xfs_bmbt_get_startblock(ep))) { arp->l0 = cpu_to_be64(ep->l0); arp->l1 = cpu_to_be64(ep->l1); arp++; cnt++; } } ASSERT(cnt == XFS_IFORK_NEXTENTS(ip, whichfork)); xfs_btree_set_numrecs(ablock, cnt); /* * Fill in the root key and pointer. */ kp = XFS_BMBT_KEY_ADDR(mp, block, 1); arp = XFS_BMBT_REC_ADDR(mp, ablock, 1); kp->br_startoff = cpu_to_be64(xfs_bmbt_disk_get_startoff(arp)); pp = XFS_BMBT_PTR_ADDR(mp, block, 1, xfs_bmbt_get_maxrecs(cur, be16_to_cpu(block->bb_level))); *pp = cpu_to_be64(args.fsbno); /* * Do all this logging at the end so that * the root is at the right level. */ xfs_btree_log_block(cur, abp, XFS_BB_ALL_BITS); xfs_btree_log_recs(cur, abp, 1, be16_to_cpu(ablock->bb_numrecs)); ASSERT(*curp == NULL); *curp = cur; *logflagsp = XFS_ILOG_CORE | xfs_ilog_fbroot(whichfork); return 0; } /* * Convert a local file to an extents file. * This code is out of bounds for data forks of regular files, * since the file data needs to get logged so things will stay consistent. * (The bmap-level manipulations are ok, though). */ void xfs_bmap_local_to_extents_empty( struct xfs_inode *ip, int whichfork) { struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, whichfork); ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL); ASSERT(ifp->if_bytes == 0); ASSERT(XFS_IFORK_NEXTENTS(ip, whichfork) == 0); xfs_bmap_forkoff_reset(ip, whichfork); ifp->if_flags &= ~XFS_IFINLINE; ifp->if_flags |= XFS_IFEXTENTS; XFS_IFORK_FMT_SET(ip, whichfork, XFS_DINODE_FMT_EXTENTS); } STATIC int /* error */ xfs_bmap_local_to_extents( xfs_trans_t *tp, /* transaction pointer */ xfs_inode_t *ip, /* incore inode pointer */ xfs_fsblock_t *firstblock, /* first block allocated in xaction */ xfs_extlen_t total, /* total blocks needed by transaction */ int *logflagsp, /* inode logging flags */ int whichfork, void (*init_fn)(struct xfs_trans *tp, struct xfs_buf *bp, struct xfs_inode *ip, struct xfs_ifork *ifp)) { int error = 0; int flags; /* logging flags returned */ xfs_ifork_t *ifp; /* inode fork pointer */ xfs_alloc_arg_t args; /* allocation arguments */ xfs_buf_t *bp; /* buffer for extent block */ xfs_bmbt_rec_host_t *ep; /* extent record pointer */ /* * We don't want to deal with the case of keeping inode data inline yet. * So sending the data fork of a regular inode is invalid. */ ASSERT(!(S_ISREG(ip->i_d.di_mode) && whichfork == XFS_DATA_FORK)); ifp = XFS_IFORK_PTR(ip, whichfork); ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL); if (!ifp->if_bytes) { xfs_bmap_local_to_extents_empty(ip, whichfork); flags = XFS_ILOG_CORE; goto done; } flags = 0; error = 0; ASSERT((ifp->if_flags & (XFS_IFINLINE|XFS_IFEXTENTS|XFS_IFEXTIREC)) == XFS_IFINLINE); memset(&args, 0, sizeof(args)); args.tp = tp; args.mp = ip->i_mount; args.firstblock = *firstblock; /* * Allocate a block. We know we need only one, since the * file currently fits in an inode. */ if (*firstblock == NULLFSBLOCK) { args.fsbno = XFS_INO_TO_FSB(args.mp, ip->i_ino); args.type = XFS_ALLOCTYPE_START_BNO; } else { args.fsbno = *firstblock; args.type = XFS_ALLOCTYPE_NEAR_BNO; } args.total = total; args.minlen = args.maxlen = args.prod = 1; error = xfs_alloc_vextent(&args); if (error) goto done; /* Can't fail, the space was reserved. */ ASSERT(args.fsbno != NULLFSBLOCK); ASSERT(args.len == 1); *firstblock = args.fsbno; bp = xfs_btree_get_bufl(args.mp, tp, args.fsbno, 0); /* * Initialise the block and copy the data * * Note: init_fn must set the buffer log item type correctly! */ init_fn(tp, bp, ip, ifp); /* account for the change in fork size and log everything */ xfs_trans_log_buf(tp, bp, 0, ifp->if_bytes - 1); xfs_idata_realloc(ip, -ifp->if_bytes, whichfork); xfs_bmap_local_to_extents_empty(ip, whichfork); flags |= XFS_ILOG_CORE; xfs_iext_add(ifp, 0, 1); ep = xfs_iext_get_ext(ifp, 0); xfs_bmbt_set_allf(ep, 0, args.fsbno, 1, XFS_EXT_NORM); trace_xfs_bmap_post_update(ip, 0, whichfork == XFS_ATTR_FORK ? BMAP_ATTRFORK : 0, _THIS_IP_); XFS_IFORK_NEXT_SET(ip, whichfork, 1); ip->i_d.di_nblocks = 1; xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_BCOUNT, 1L); flags |= xfs_ilog_fext(whichfork); done: *logflagsp = flags; return error; } /* * Called from xfs_bmap_add_attrfork to handle btree format files. */ STATIC int /* error */ xfs_bmap_add_attrfork_btree( xfs_trans_t *tp, /* transaction pointer */ xfs_inode_t *ip, /* incore inode pointer */ xfs_fsblock_t *firstblock, /* first block allocated */ xfs_bmap_free_t *flist, /* blocks to free at commit */ int *flags) /* inode logging flags */ { xfs_btree_cur_t *cur; /* btree cursor */ int error; /* error return value */ xfs_mount_t *mp; /* file system mount struct */ int stat; /* newroot status */ mp = ip->i_mount; if (ip->i_df.if_broot_bytes <= XFS_IFORK_DSIZE(ip)) *flags |= XFS_ILOG_DBROOT; else { cur = xfs_bmbt_init_cursor(mp, tp, ip, XFS_DATA_FORK); cur->bc_private.b.flist = flist; cur->bc_private.b.firstblock = *firstblock; if ((error = xfs_bmbt_lookup_ge(cur, 0, 0, 0, &stat))) goto error0; /* must be at least one entry */ XFS_WANT_CORRUPTED_GOTO(mp, stat == 1, error0); if ((error = xfs_btree_new_iroot(cur, flags, &stat))) goto error0; if (stat == 0) { xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); return -ENOSPC; } *firstblock = cur->bc_private.b.firstblock; cur->bc_private.b.allocated = 0; xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); } return 0; error0: xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); return error; } /* * Called from xfs_bmap_add_attrfork to handle extents format files. */ STATIC int /* error */ xfs_bmap_add_attrfork_extents( xfs_trans_t *tp, /* transaction pointer */ xfs_inode_t *ip, /* incore inode pointer */ xfs_fsblock_t *firstblock, /* first block allocated */ xfs_bmap_free_t *flist, /* blocks to free at commit */ int *flags) /* inode logging flags */ { xfs_btree_cur_t *cur; /* bmap btree cursor */ int error; /* error return value */ if (ip->i_d.di_nextents * sizeof(xfs_bmbt_rec_t) <= XFS_IFORK_DSIZE(ip)) return 0; cur = NULL; error = xfs_bmap_extents_to_btree(tp, ip, firstblock, flist, &cur, 0, flags, XFS_DATA_FORK); if (cur) { cur->bc_private.b.allocated = 0; xfs_btree_del_cursor(cur, error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR); } return error; } /* * Called from xfs_bmap_add_attrfork to handle local format files. Each * different data fork content type needs a different callout to do the * conversion. Some are basic and only require special block initialisation * callouts for the data formating, others (directories) are so specialised they * handle everything themselves. * * XXX (dgc): investigate whether directory conversion can use the generic * formatting callout. It should be possible - it's just a very complex * formatter. */ STATIC int /* error */ xfs_bmap_add_attrfork_local( xfs_trans_t *tp, /* transaction pointer */ xfs_inode_t *ip, /* incore inode pointer */ xfs_fsblock_t *firstblock, /* first block allocated */ xfs_bmap_free_t *flist, /* blocks to free at commit */ int *flags) /* inode logging flags */ { xfs_da_args_t dargs; /* args for dir/attr code */ if (ip->i_df.if_bytes <= XFS_IFORK_DSIZE(ip)) return 0; if (S_ISDIR(ip->i_d.di_mode)) { memset(&dargs, 0, sizeof(dargs)); dargs.geo = ip->i_mount->m_dir_geo; dargs.dp = ip; dargs.firstblock = firstblock; dargs.flist = flist; dargs.total = dargs.geo->fsbcount; dargs.whichfork = XFS_DATA_FORK; dargs.trans = tp; return xfs_dir2_sf_to_block(&dargs); } if (S_ISLNK(ip->i_d.di_mode)) return xfs_bmap_local_to_extents(tp, ip, firstblock, 1, flags, XFS_DATA_FORK, xfs_symlink_local_to_remote); /* should only be called for types that support local format data */ ASSERT(0); return -EFSCORRUPTED; } /* * Convert inode from non-attributed to attributed. * Must not be in a transaction, ip must not be locked. */ int /* error code */ xfs_bmap_add_attrfork( xfs_inode_t *ip, /* incore inode pointer */ int size, /* space new attribute needs */ int rsvd) /* xact may use reserved blks */ { xfs_fsblock_t firstblock; /* 1st block/ag allocated */ xfs_bmap_free_t flist; /* freed extent records */ xfs_mount_t *mp; /* mount structure */ xfs_trans_t *tp; /* transaction pointer */ int blks; /* space reservation */ int version = 1; /* superblock attr version */ int committed; /* xaction was committed */ int logflags; /* logging flags */ int error; /* error return value */ ASSERT(XFS_IFORK_Q(ip) == 0); mp = ip->i_mount; ASSERT(!XFS_NOT_DQATTACHED(mp, ip)); tp = xfs_trans_alloc(mp, XFS_TRANS_ADDAFORK); blks = XFS_ADDAFORK_SPACE_RES(mp); if (rsvd) tp->t_flags |= XFS_TRANS_RESERVE; error = xfs_trans_reserve(tp, &M_RES(mp)->tr_addafork, blks, 0); if (error) { xfs_trans_cancel(tp); return error; } xfs_ilock(ip, XFS_ILOCK_EXCL); error = xfs_trans_reserve_quota_nblks(tp, ip, blks, 0, rsvd ? XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_FORCE_RES : XFS_QMOPT_RES_REGBLKS); if (error) goto trans_cancel; if (XFS_IFORK_Q(ip)) goto trans_cancel; if (ip->i_d.di_aformat != XFS_DINODE_FMT_EXTENTS) { /* * For inodes coming from pre-6.2 filesystems. */ ASSERT(ip->i_d.di_aformat == 0); ip->i_d.di_aformat = XFS_DINODE_FMT_EXTENTS; } ASSERT(ip->i_d.di_anextents == 0); xfs_trans_ijoin(tp, ip, 0); xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); switch (ip->i_d.di_format) { case XFS_DINODE_FMT_DEV: ip->i_d.di_forkoff = roundup(sizeof(xfs_dev_t), 8) >> 3; break; case XFS_DINODE_FMT_UUID: ip->i_d.di_forkoff = roundup(sizeof(uuid_t), 8) >> 3; break; case XFS_DINODE_FMT_LOCAL: case XFS_DINODE_FMT_EXTENTS: case XFS_DINODE_FMT_BTREE: ip->i_d.di_forkoff = xfs_attr_shortform_bytesfit(ip, size); if (!ip->i_d.di_forkoff) ip->i_d.di_forkoff = xfs_default_attroffset(ip) >> 3; else if (mp->m_flags & XFS_MOUNT_ATTR2) version = 2; break; default: ASSERT(0); error = -EINVAL; goto trans_cancel; } ASSERT(ip->i_afp == NULL); ip->i_afp = kmem_zone_zalloc(xfs_ifork_zone, KM_SLEEP); ip->i_afp->if_flags = XFS_IFEXTENTS; logflags = 0; xfs_bmap_init(&flist, &firstblock); switch (ip->i_d.di_format) { case XFS_DINODE_FMT_LOCAL: error = xfs_bmap_add_attrfork_local(tp, ip, &firstblock, &flist, &logflags); break; case XFS_DINODE_FMT_EXTENTS: error = xfs_bmap_add_attrfork_extents(tp, ip, &firstblock, &flist, &logflags); break; case XFS_DINODE_FMT_BTREE: error = xfs_bmap_add_attrfork_btree(tp, ip, &firstblock, &flist, &logflags); break; default: error = 0; break; } if (logflags) xfs_trans_log_inode(tp, ip, logflags); if (error) goto bmap_cancel; if (!xfs_sb_version_hasattr(&mp->m_sb) || (!xfs_sb_version_hasattr2(&mp->m_sb) && version == 2)) { bool log_sb = false; spin_lock(&mp->m_sb_lock); if (!xfs_sb_version_hasattr(&mp->m_sb)) { xfs_sb_version_addattr(&mp->m_sb); log_sb = true; } if (!xfs_sb_version_hasattr2(&mp->m_sb) && version == 2) { xfs_sb_version_addattr2(&mp->m_sb); log_sb = true; } spin_unlock(&mp->m_sb_lock); if (log_sb) xfs_log_sb(tp); } error = xfs_bmap_finish(&tp, &flist, &committed); if (error) goto bmap_cancel; error = xfs_trans_commit(tp); xfs_iunlock(ip, XFS_ILOCK_EXCL); return error; bmap_cancel: xfs_bmap_cancel(&flist); trans_cancel: xfs_trans_cancel(tp); xfs_iunlock(ip, XFS_ILOCK_EXCL); return error; } /* * Internal and external extent tree search functions. */ /* * Read in the extents to if_extents. * All inode fields are set up by caller, we just traverse the btree * and copy the records in. If the file system cannot contain unwritten * extents, the records are checked for no "state" flags. */ int /* error */ xfs_bmap_read_extents( xfs_trans_t *tp, /* transaction pointer */ xfs_inode_t *ip, /* incore inode */ int whichfork) /* data or attr fork */ { struct xfs_btree_block *block; /* current btree block */ xfs_fsblock_t bno; /* block # of "block" */ xfs_buf_t *bp; /* buffer for "block" */ int error; /* error return value */ xfs_exntfmt_t exntf; /* XFS_EXTFMT_NOSTATE, if checking */ xfs_extnum_t i, j; /* index into the extents list */ xfs_ifork_t *ifp; /* fork structure */ int level; /* btree level, for checking */ xfs_mount_t *mp; /* file system mount structure */ __be64 *pp; /* pointer to block address */ /* REFERENCED */ xfs_extnum_t room; /* number of entries there's room for */ bno = NULLFSBLOCK; mp = ip->i_mount; ifp = XFS_IFORK_PTR(ip, whichfork); exntf = (whichfork != XFS_DATA_FORK) ? XFS_EXTFMT_NOSTATE : XFS_EXTFMT_INODE(ip); block = ifp->if_broot; /* * Root level must use BMAP_BROOT_PTR_ADDR macro to get ptr out. */ level = be16_to_cpu(block->bb_level); ASSERT(level > 0); pp = XFS_BMAP_BROOT_PTR_ADDR(mp, block, 1, ifp->if_broot_bytes); bno = be64_to_cpu(*pp); ASSERT(bno != NULLFSBLOCK); ASSERT(XFS_FSB_TO_AGNO(mp, bno) < mp->m_sb.sb_agcount); ASSERT(XFS_FSB_TO_AGBNO(mp, bno) < mp->m_sb.sb_agblocks); /* * Go down the tree until leaf level is reached, following the first * pointer (leftmost) at each level. */ while (level-- > 0) { error = xfs_btree_read_bufl(mp, tp, bno, 0, &bp, XFS_BMAP_BTREE_REF, &xfs_bmbt_buf_ops); if (error) return error; block = XFS_BUF_TO_BLOCK(bp); if (level == 0) break; pp = XFS_BMBT_PTR_ADDR(mp, block, 1, mp->m_bmap_dmxr[1]); bno = be64_to_cpu(*pp); XFS_WANT_CORRUPTED_GOTO(mp, XFS_FSB_SANITY_CHECK(mp, bno), error0); xfs_trans_brelse(tp, bp); } /* * Here with bp and block set to the leftmost leaf node in the tree. */ room = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); i = 0; /* * Loop over all leaf nodes. Copy information to the extent records. */ for (;;) { xfs_bmbt_rec_t *frp; xfs_fsblock_t nextbno; xfs_extnum_t num_recs; xfs_extnum_t start; num_recs = xfs_btree_get_numrecs(block); if (unlikely(i + num_recs > room)) { ASSERT(i + num_recs <= room); xfs_warn(ip->i_mount, "corrupt dinode %Lu, (btree extents).", (unsigned long long) ip->i_ino); XFS_CORRUPTION_ERROR("xfs_bmap_read_extents(1)", XFS_ERRLEVEL_LOW, ip->i_mount, block); goto error0; } /* * Read-ahead the next leaf block, if any. */ nextbno = be64_to_cpu(block->bb_u.l.bb_rightsib); if (nextbno != NULLFSBLOCK) xfs_btree_reada_bufl(mp, nextbno, 1, &xfs_bmbt_buf_ops); /* * Copy records into the extent records. */ frp = XFS_BMBT_REC_ADDR(mp, block, 1); start = i; for (j = 0; j < num_recs; j++, i++, frp++) { xfs_bmbt_rec_host_t *trp = xfs_iext_get_ext(ifp, i); trp->l0 = be64_to_cpu(frp->l0); trp->l1 = be64_to_cpu(frp->l1); } if (exntf == XFS_EXTFMT_NOSTATE) { /* * Check all attribute bmap btree records and * any "older" data bmap btree records for a * set bit in the "extent flag" position. */ if (unlikely(xfs_check_nostate_extents(ifp, start, num_recs))) { XFS_ERROR_REPORT("xfs_bmap_read_extents(2)", XFS_ERRLEVEL_LOW, ip->i_mount); goto error0; } } xfs_trans_brelse(tp, bp); bno = nextbno; /* * If we've reached the end, stop. */ if (bno == NULLFSBLOCK) break; error = xfs_btree_read_bufl(mp, tp, bno, 0, &bp, XFS_BMAP_BTREE_REF, &xfs_bmbt_buf_ops); if (error) return error; block = XFS_BUF_TO_BLOCK(bp); } ASSERT(i == (ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t))); ASSERT(i == XFS_IFORK_NEXTENTS(ip, whichfork)); XFS_BMAP_TRACE_EXLIST(ip, i, whichfork); return 0; error0: xfs_trans_brelse(tp, bp); return -EFSCORRUPTED; } /* * Search the extent records for the entry containing block bno. * If bno lies in a hole, point to the next entry. If bno lies * past eof, *eofp will be set, and *prevp will contain the last * entry (null if none). Else, *lastxp will be set to the index * of the found entry; *gotp will contain the entry. */ STATIC xfs_bmbt_rec_host_t * /* pointer to found extent entry */ xfs_bmap_search_multi_extents( xfs_ifork_t *ifp, /* inode fork pointer */ xfs_fileoff_t bno, /* block number searched for */ int *eofp, /* out: end of file found */ xfs_extnum_t *lastxp, /* out: last extent index */ xfs_bmbt_irec_t *gotp, /* out: extent entry found */ xfs_bmbt_irec_t *prevp) /* out: previous extent entry found */ { xfs_bmbt_rec_host_t *ep; /* extent record pointer */ xfs_extnum_t lastx; /* last extent index */ /* * Initialize the extent entry structure to catch access to * uninitialized br_startblock field. */ gotp->br_startoff = 0xffa5a5a5a5a5a5a5LL; gotp->br_blockcount = 0xa55a5a5a5a5a5a5aLL; gotp->br_state = XFS_EXT_INVALID; gotp->br_startblock = 0xffffa5a5a5a5a5a5LL; prevp->br_startoff = NULLFILEOFF; ep = xfs_iext_bno_to_ext(ifp, bno, &lastx); if (lastx > 0) { xfs_bmbt_get_all(xfs_iext_get_ext(ifp, lastx - 1), prevp); } if (lastx < (ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t))) { xfs_bmbt_get_all(ep, gotp); *eofp = 0; } else { if (lastx > 0) { *gotp = *prevp; } *eofp = 1; ep = NULL; } *lastxp = lastx; return ep; } /* * Search the extents list for the inode, for the extent containing bno. * If bno lies in a hole, point to the next entry. If bno lies past eof, * *eofp will be set, and *prevp will contain the last entry (null if none). * Else, *lastxp will be set to the index of the found * entry; *gotp will contain the entry. */ xfs_bmbt_rec_host_t * /* pointer to found extent entry */ xfs_bmap_search_extents( xfs_inode_t *ip, /* incore inode pointer */ xfs_fileoff_t bno, /* block number searched for */ int fork, /* data or attr fork */ int *eofp, /* out: end of file found */ xfs_extnum_t *lastxp, /* out: last extent index */ xfs_bmbt_irec_t *gotp, /* out: extent entry found */ xfs_bmbt_irec_t *prevp) /* out: previous extent entry found */ { xfs_ifork_t *ifp; /* inode fork pointer */ xfs_bmbt_rec_host_t *ep; /* extent record pointer */ XFS_STATS_INC(xs_look_exlist); ifp = XFS_IFORK_PTR(ip, fork); ep = xfs_bmap_search_multi_extents(ifp, bno, eofp, lastxp, gotp, prevp); if (unlikely(!(gotp->br_startblock) && (*lastxp != NULLEXTNUM) && !(XFS_IS_REALTIME_INODE(ip) && fork == XFS_DATA_FORK))) { xfs_alert_tag(ip->i_mount, XFS_PTAG_FSBLOCK_ZERO, "Access to block zero in inode %llu " "start_block: %llx start_off: %llx " "blkcnt: %llx extent-state: %x lastx: %x", (unsigned long long)ip->i_ino, (unsigned long long)gotp->br_startblock, (unsigned long long)gotp->br_startoff, (unsigned long long)gotp->br_blockcount, gotp->br_state, *lastxp); *lastxp = NULLEXTNUM; *eofp = 1; return NULL; } return ep; } /* * Returns the file-relative block number of the first unused block(s) * in the file with at least "len" logically contiguous blocks free. * This is the lowest-address hole if the file has holes, else the first block * past the end of file. * Return 0 if the file is currently local (in-inode). */ int /* error */ xfs_bmap_first_unused( xfs_trans_t *tp, /* transaction pointer */ xfs_inode_t *ip, /* incore inode */ xfs_extlen_t len, /* size of hole to find */ xfs_fileoff_t *first_unused, /* unused block */ int whichfork) /* data or attr fork */ { int error; /* error return value */ int idx; /* extent record index */ xfs_ifork_t *ifp; /* inode fork pointer */ xfs_fileoff_t lastaddr; /* last block number seen */ xfs_fileoff_t lowest; /* lowest useful block */ xfs_fileoff_t max; /* starting useful block */ xfs_fileoff_t off; /* offset for this block */ xfs_extnum_t nextents; /* number of extent entries */ ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE || XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_EXTENTS || XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL); if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL) { *first_unused = 0; return 0; } ifp = XFS_IFORK_PTR(ip, whichfork); if (!(ifp->if_flags & XFS_IFEXTENTS) && (error = xfs_iread_extents(tp, ip, whichfork))) return error; lowest = *first_unused; nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); for (idx = 0, lastaddr = 0, max = lowest; idx < nextents; idx++) { xfs_bmbt_rec_host_t *ep = xfs_iext_get_ext(ifp, idx); off = xfs_bmbt_get_startoff(ep); /* * See if the hole before this extent will work. */ if (off >= lowest + len && off - max >= len) { *first_unused = max; return 0; } lastaddr = off + xfs_bmbt_get_blockcount(ep); max = XFS_FILEOFF_MAX(lastaddr, lowest); } *first_unused = max; return 0; } /* * Returns the file-relative block number of the last block - 1 before * last_block (input value) in the file. * This is not based on i_size, it is based on the extent records. * Returns 0 for local files, as they do not have extent records. */ int /* error */ xfs_bmap_last_before( xfs_trans_t *tp, /* transaction pointer */ xfs_inode_t *ip, /* incore inode */ xfs_fileoff_t *last_block, /* last block */ int whichfork) /* data or attr fork */ { xfs_fileoff_t bno; /* input file offset */ int eof; /* hit end of file */ xfs_bmbt_rec_host_t *ep; /* pointer to last extent */ int error; /* error return value */ xfs_bmbt_irec_t got; /* current extent value */ xfs_ifork_t *ifp; /* inode fork pointer */ xfs_extnum_t lastx; /* last extent used */ xfs_bmbt_irec_t prev; /* previous extent value */ if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE && XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS && XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_LOCAL) return -EIO; if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL) { *last_block = 0; return 0; } ifp = XFS_IFORK_PTR(ip, whichfork); if (!(ifp->if_flags & XFS_IFEXTENTS) && (error = xfs_iread_extents(tp, ip, whichfork))) return error; bno = *last_block - 1; ep = xfs_bmap_search_extents(ip, bno, whichfork, &eof, &lastx, &got, &prev); if (eof || xfs_bmbt_get_startoff(ep) > bno) { if (prev.br_startoff == NULLFILEOFF) *last_block = 0; else *last_block = prev.br_startoff + prev.br_blockcount; } /* * Otherwise *last_block is already the right answer. */ return 0; } int xfs_bmap_last_extent( struct xfs_trans *tp, struct xfs_inode *ip, int whichfork, struct xfs_bmbt_irec *rec, int *is_empty) { struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, whichfork); int error; int nextents; if (!(ifp->if_flags & XFS_IFEXTENTS)) { error = xfs_iread_extents(tp, ip, whichfork); if (error) return error; } nextents = ifp->if_bytes / sizeof(xfs_bmbt_rec_t); if (nextents == 0) { *is_empty = 1; return 0; } xfs_bmbt_get_all(xfs_iext_get_ext(ifp, nextents - 1), rec); *is_empty = 0; return 0; } /* * Check the last inode extent to determine whether this allocation will result * in blocks being allocated at the end of the file. When we allocate new data * blocks at the end of the file which do not start at the previous data block, * we will try to align the new blocks at stripe unit boundaries. * * Returns 1 in bma->aeof if the file (fork) is empty as any new write will be * at, or past the EOF. */ STATIC int xfs_bmap_isaeof( struct xfs_bmalloca *bma, int whichfork) { struct xfs_bmbt_irec rec; int is_empty; int error; bma->aeof = 0; error = xfs_bmap_last_extent(NULL, bma->ip, whichfork, &rec, &is_empty); if (error) return error; if (is_empty) { bma->aeof = 1; return 0; } /* * Check if we are allocation or past the last extent, or at least into * the last delayed allocated extent. */ bma->aeof = bma->offset >= rec.br_startoff + rec.br_blockcount || (bma->offset >= rec.br_startoff && isnullstartblock(rec.br_startblock)); return 0; } /* * Returns the file-relative block number of the first block past eof in * the file. This is not based on i_size, it is based on the extent records. * Returns 0 for local files, as they do not have extent records. */ int xfs_bmap_last_offset( struct xfs_inode *ip, xfs_fileoff_t *last_block, int whichfork) { struct xfs_bmbt_irec rec; int is_empty; int error; *last_block = 0; if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL) return 0; if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE && XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS) return -EIO; error = xfs_bmap_last_extent(NULL, ip, whichfork, &rec, &is_empty); if (error || is_empty) return error; *last_block = rec.br_startoff + rec.br_blockcount; return 0; } /* * Returns whether the selected fork of the inode has exactly one * block or not. For the data fork we check this matches di_size, * implying the file's range is 0..bsize-1. */ int /* 1=>1 block, 0=>otherwise */ xfs_bmap_one_block( xfs_inode_t *ip, /* incore inode */ int whichfork) /* data or attr fork */ { xfs_bmbt_rec_host_t *ep; /* ptr to fork's extent */ xfs_ifork_t *ifp; /* inode fork pointer */ int rval; /* return value */ xfs_bmbt_irec_t s; /* internal version of extent */ #ifndef DEBUG if (whichfork == XFS_DATA_FORK) return XFS_ISIZE(ip) == ip->i_mount->m_sb.sb_blocksize; #endif /* !DEBUG */ if (XFS_IFORK_NEXTENTS(ip, whichfork) != 1) return 0; if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS) return 0; ifp = XFS_IFORK_PTR(ip, whichfork); ASSERT(ifp->if_flags & XFS_IFEXTENTS); ep = xfs_iext_get_ext(ifp, 0); xfs_bmbt_get_all(ep, &s); rval = s.br_startoff == 0 && s.br_blockcount == 1; if (rval && whichfork == XFS_DATA_FORK) ASSERT(XFS_ISIZE(ip) == ip->i_mount->m_sb.sb_blocksize); return rval; } /* * Extent tree manipulation functions used during allocation. */ /* * Convert a delayed allocation to a real allocation. */ STATIC int /* error */ xfs_bmap_add_extent_delay_real( struct xfs_bmalloca *bma) { struct xfs_bmbt_irec *new = &bma->got; int diff; /* temp value */ xfs_bmbt_rec_host_t *ep; /* extent entry for idx */ int error; /* error return value */ int i; /* temp state */ xfs_ifork_t *ifp; /* inode fork pointer */ xfs_fileoff_t new_endoff; /* end offset of new entry */ xfs_bmbt_irec_t r[3]; /* neighbor extent entries */ /* left is 0, right is 1, prev is 2 */ int rval=0; /* return value (logging flags) */ int state = 0;/* state bits, accessed thru macros */ xfs_filblks_t da_new; /* new count del alloc blocks used */ xfs_filblks_t da_old; /* old count del alloc blocks used */ xfs_filblks_t temp=0; /* value for da_new calculations */ xfs_filblks_t temp2=0;/* value for da_new calculations */ int tmp_rval; /* partial logging flags */ struct xfs_mount *mp; mp = bma->tp ? bma->tp->t_mountp : NULL; ifp = XFS_IFORK_PTR(bma->ip, XFS_DATA_FORK); ASSERT(bma->idx >= 0); ASSERT(bma->idx <= ifp->if_bytes / sizeof(struct xfs_bmbt_rec)); ASSERT(!isnullstartblock(new->br_startblock)); ASSERT(!bma->cur || (bma->cur->bc_private.b.flags & XFS_BTCUR_BPRV_WASDEL)); XFS_STATS_INC(xs_add_exlist); #define LEFT r[0] #define RIGHT r[1] #define PREV r[2] /* * Set up a bunch of variables to make the tests simpler. */ ep = xfs_iext_get_ext(ifp, bma->idx); xfs_bmbt_get_all(ep, &PREV); new_endoff = new->br_startoff + new->br_blockcount; ASSERT(PREV.br_startoff <= new->br_startoff); ASSERT(PREV.br_startoff + PREV.br_blockcount >= new_endoff); da_old = startblockval(PREV.br_startblock); da_new = 0; /* * Set flags determining what part of the previous delayed allocation * extent is being replaced by a real allocation. */ if (PREV.br_startoff == new->br_startoff) state |= BMAP_LEFT_FILLING; if (PREV.br_startoff + PREV.br_blockcount == new_endoff) state |= BMAP_RIGHT_FILLING; /* * Check and set flags if this segment has a left neighbor. * Don't set contiguous if the combined extent would be too large. */ if (bma->idx > 0) { state |= BMAP_LEFT_VALID; xfs_bmbt_get_all(xfs_iext_get_ext(ifp, bma->idx - 1), &LEFT); if (isnullstartblock(LEFT.br_startblock)) state |= BMAP_LEFT_DELAY; } if ((state & BMAP_LEFT_VALID) && !(state & BMAP_LEFT_DELAY) && LEFT.br_startoff + LEFT.br_blockcount == new->br_startoff && LEFT.br_startblock + LEFT.br_blockcount == new->br_startblock && LEFT.br_state == new->br_state && LEFT.br_blockcount + new->br_blockcount <= MAXEXTLEN) state |= BMAP_LEFT_CONTIG; /* * Check and set flags if this segment has a right neighbor. * Don't set contiguous if the combined extent would be too large. * Also check for all-three-contiguous being too large. */ if (bma->idx < bma->ip->i_df.if_bytes / (uint)sizeof(xfs_bmbt_rec_t) - 1) { state |= BMAP_RIGHT_VALID; xfs_bmbt_get_all(xfs_iext_get_ext(ifp, bma->idx + 1), &RIGHT); if (isnullstartblock(RIGHT.br_startblock)) state |= BMAP_RIGHT_DELAY; } if ((state & BMAP_RIGHT_VALID) && !(state & BMAP_RIGHT_DELAY) && new_endoff == RIGHT.br_startoff && new->br_startblock + new->br_blockcount == RIGHT.br_startblock && new->br_state == RIGHT.br_state && new->br_blockcount + RIGHT.br_blockcount <= MAXEXTLEN && ((state & (BMAP_LEFT_CONTIG | BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING)) != (BMAP_LEFT_CONTIG | BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING) || LEFT.br_blockcount + new->br_blockcount + RIGHT.br_blockcount <= MAXEXTLEN)) state |= BMAP_RIGHT_CONTIG; error = 0; /* * Switch out based on the FILLING and CONTIG state bits. */ switch (state & (BMAP_LEFT_FILLING | BMAP_LEFT_CONTIG | BMAP_RIGHT_FILLING | BMAP_RIGHT_CONTIG)) { case BMAP_LEFT_FILLING | BMAP_LEFT_CONTIG | BMAP_RIGHT_FILLING | BMAP_RIGHT_CONTIG: /* * Filling in all of a previously delayed allocation extent. * The left and right neighbors are both contiguous with new. */ bma->idx--; trace_xfs_bmap_pre_update(bma->ip, bma->idx, state, _THIS_IP_); xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, bma->idx), LEFT.br_blockcount + PREV.br_blockcount + RIGHT.br_blockcount); trace_xfs_bmap_post_update(bma->ip, bma->idx, state, _THIS_IP_); xfs_iext_remove(bma->ip, bma->idx + 1, 2, state); bma->ip->i_d.di_nextents--; if (bma->cur == NULL) rval = XFS_ILOG_CORE | XFS_ILOG_DEXT; else { rval = XFS_ILOG_CORE; error = xfs_bmbt_lookup_eq(bma->cur, RIGHT.br_startoff, RIGHT.br_startblock, RIGHT.br_blockcount, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); error = xfs_btree_delete(bma->cur, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); error = xfs_btree_decrement(bma->cur, 0, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); error = xfs_bmbt_update(bma->cur, LEFT.br_startoff, LEFT.br_startblock, LEFT.br_blockcount + PREV.br_blockcount + RIGHT.br_blockcount, LEFT.br_state); if (error) goto done; } break; case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING | BMAP_LEFT_CONTIG: /* * Filling in all of a previously delayed allocation extent. * The left neighbor is contiguous, the right is not. */ bma->idx--; trace_xfs_bmap_pre_update(bma->ip, bma->idx, state, _THIS_IP_); xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, bma->idx), LEFT.br_blockcount + PREV.br_blockcount); trace_xfs_bmap_post_update(bma->ip, bma->idx, state, _THIS_IP_); xfs_iext_remove(bma->ip, bma->idx + 1, 1, state); if (bma->cur == NULL) rval = XFS_ILOG_DEXT; else { rval = 0; error = xfs_bmbt_lookup_eq(bma->cur, LEFT.br_startoff, LEFT.br_startblock, LEFT.br_blockcount, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); error = xfs_bmbt_update(bma->cur, LEFT.br_startoff, LEFT.br_startblock, LEFT.br_blockcount + PREV.br_blockcount, LEFT.br_state); if (error) goto done; } break; case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING | BMAP_RIGHT_CONTIG: /* * Filling in all of a previously delayed allocation extent. * The right neighbor is contiguous, the left is not. */ trace_xfs_bmap_pre_update(bma->ip, bma->idx, state, _THIS_IP_); xfs_bmbt_set_startblock(ep, new->br_startblock); xfs_bmbt_set_blockcount(ep, PREV.br_blockcount + RIGHT.br_blockcount); trace_xfs_bmap_post_update(bma->ip, bma->idx, state, _THIS_IP_); xfs_iext_remove(bma->ip, bma->idx + 1, 1, state); if (bma->cur == NULL) rval = XFS_ILOG_DEXT; else { rval = 0; error = xfs_bmbt_lookup_eq(bma->cur, RIGHT.br_startoff, RIGHT.br_startblock, RIGHT.br_blockcount, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); error = xfs_bmbt_update(bma->cur, PREV.br_startoff, new->br_startblock, PREV.br_blockcount + RIGHT.br_blockcount, PREV.br_state); if (error) goto done; } break; case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING: /* * Filling in all of a previously delayed allocation extent. * Neither the left nor right neighbors are contiguous with * the new one. */ trace_xfs_bmap_pre_update(bma->ip, bma->idx, state, _THIS_IP_); xfs_bmbt_set_startblock(ep, new->br_startblock); trace_xfs_bmap_post_update(bma->ip, bma->idx, state, _THIS_IP_); bma->ip->i_d.di_nextents++; if (bma->cur == NULL) rval = XFS_ILOG_CORE | XFS_ILOG_DEXT; else { rval = XFS_ILOG_CORE; error = xfs_bmbt_lookup_eq(bma->cur, new->br_startoff, new->br_startblock, new->br_blockcount, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 0, done); bma->cur->bc_rec.b.br_state = XFS_EXT_NORM; error = xfs_btree_insert(bma->cur, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); } break; case BMAP_LEFT_FILLING | BMAP_LEFT_CONTIG: /* * Filling in the first part of a previous delayed allocation. * The left neighbor is contiguous. */ trace_xfs_bmap_pre_update(bma->ip, bma->idx - 1, state, _THIS_IP_); xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, bma->idx - 1), LEFT.br_blockcount + new->br_blockcount); xfs_bmbt_set_startoff(ep, PREV.br_startoff + new->br_blockcount); trace_xfs_bmap_post_update(bma->ip, bma->idx - 1, state, _THIS_IP_); temp = PREV.br_blockcount - new->br_blockcount; trace_xfs_bmap_pre_update(bma->ip, bma->idx, state, _THIS_IP_); xfs_bmbt_set_blockcount(ep, temp); if (bma->cur == NULL) rval = XFS_ILOG_DEXT; else { rval = 0; error = xfs_bmbt_lookup_eq(bma->cur, LEFT.br_startoff, LEFT.br_startblock, LEFT.br_blockcount, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); error = xfs_bmbt_update(bma->cur, LEFT.br_startoff, LEFT.br_startblock, LEFT.br_blockcount + new->br_blockcount, LEFT.br_state); if (error) goto done; } da_new = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(bma->ip, temp), startblockval(PREV.br_startblock)); xfs_bmbt_set_startblock(ep, nullstartblock(da_new)); trace_xfs_bmap_post_update(bma->ip, bma->idx, state, _THIS_IP_); bma->idx--; break; case BMAP_LEFT_FILLING: /* * Filling in the first part of a previous delayed allocation. * The left neighbor is not contiguous. */ trace_xfs_bmap_pre_update(bma->ip, bma->idx, state, _THIS_IP_); xfs_bmbt_set_startoff(ep, new_endoff); temp = PREV.br_blockcount - new->br_blockcount; xfs_bmbt_set_blockcount(ep, temp); xfs_iext_insert(bma->ip, bma->idx, 1, new, state); bma->ip->i_d.di_nextents++; if (bma->cur == NULL) rval = XFS_ILOG_CORE | XFS_ILOG_DEXT; else { rval = XFS_ILOG_CORE; error = xfs_bmbt_lookup_eq(bma->cur, new->br_startoff, new->br_startblock, new->br_blockcount, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 0, done); bma->cur->bc_rec.b.br_state = XFS_EXT_NORM; error = xfs_btree_insert(bma->cur, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); } if (xfs_bmap_needs_btree(bma->ip, XFS_DATA_FORK)) { error = xfs_bmap_extents_to_btree(bma->tp, bma->ip, bma->firstblock, bma->flist, &bma->cur, 1, &tmp_rval, XFS_DATA_FORK); rval |= tmp_rval; if (error) goto done; } da_new = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(bma->ip, temp), startblockval(PREV.br_startblock) - (bma->cur ? bma->cur->bc_private.b.allocated : 0)); ep = xfs_iext_get_ext(ifp, bma->idx + 1); xfs_bmbt_set_startblock(ep, nullstartblock(da_new)); trace_xfs_bmap_post_update(bma->ip, bma->idx + 1, state, _THIS_IP_); break; case BMAP_RIGHT_FILLING | BMAP_RIGHT_CONTIG: /* * Filling in the last part of a previous delayed allocation. * The right neighbor is contiguous with the new allocation. */ temp = PREV.br_blockcount - new->br_blockcount; trace_xfs_bmap_pre_update(bma->ip, bma->idx + 1, state, _THIS_IP_); xfs_bmbt_set_blockcount(ep, temp); xfs_bmbt_set_allf(xfs_iext_get_ext(ifp, bma->idx + 1), new->br_startoff, new->br_startblock, new->br_blockcount + RIGHT.br_blockcount, RIGHT.br_state); trace_xfs_bmap_post_update(bma->ip, bma->idx + 1, state, _THIS_IP_); if (bma->cur == NULL) rval = XFS_ILOG_DEXT; else { rval = 0; error = xfs_bmbt_lookup_eq(bma->cur, RIGHT.br_startoff, RIGHT.br_startblock, RIGHT.br_blockcount, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); error = xfs_bmbt_update(bma->cur, new->br_startoff, new->br_startblock, new->br_blockcount + RIGHT.br_blockcount, RIGHT.br_state); if (error) goto done; } da_new = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(bma->ip, temp), startblockval(PREV.br_startblock)); trace_xfs_bmap_pre_update(bma->ip, bma->idx, state, _THIS_IP_); xfs_bmbt_set_startblock(ep, nullstartblock(da_new)); trace_xfs_bmap_post_update(bma->ip, bma->idx, state, _THIS_IP_); bma->idx++; break; case BMAP_RIGHT_FILLING: /* * Filling in the last part of a previous delayed allocation. * The right neighbor is not contiguous. */ temp = PREV.br_blockcount - new->br_blockcount; trace_xfs_bmap_pre_update(bma->ip, bma->idx, state, _THIS_IP_); xfs_bmbt_set_blockcount(ep, temp); xfs_iext_insert(bma->ip, bma->idx + 1, 1, new, state); bma->ip->i_d.di_nextents++; if (bma->cur == NULL) rval = XFS_ILOG_CORE | XFS_ILOG_DEXT; else { rval = XFS_ILOG_CORE; error = xfs_bmbt_lookup_eq(bma->cur, new->br_startoff, new->br_startblock, new->br_blockcount, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 0, done); bma->cur->bc_rec.b.br_state = XFS_EXT_NORM; error = xfs_btree_insert(bma->cur, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); } if (xfs_bmap_needs_btree(bma->ip, XFS_DATA_FORK)) { error = xfs_bmap_extents_to_btree(bma->tp, bma->ip, bma->firstblock, bma->flist, &bma->cur, 1, &tmp_rval, XFS_DATA_FORK); rval |= tmp_rval; if (error) goto done; } da_new = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(bma->ip, temp), startblockval(PREV.br_startblock) - (bma->cur ? bma->cur->bc_private.b.allocated : 0)); ep = xfs_iext_get_ext(ifp, bma->idx); xfs_bmbt_set_startblock(ep, nullstartblock(da_new)); trace_xfs_bmap_post_update(bma->ip, bma->idx, state, _THIS_IP_); bma->idx++; break; case 0: /* * Filling in the middle part of a previous delayed allocation. * Contiguity is impossible here. * This case is avoided almost all the time. * * We start with a delayed allocation: * * +ddddddddddddddddddddddddddddddddddddddddddddddddddddddd+ * PREV @ idx * * and we are allocating: * +rrrrrrrrrrrrrrrrr+ * new * * and we set it up for insertion as: * +ddddddddddddddddddd+rrrrrrrrrrrrrrrrr+ddddddddddddddddd+ * new * PREV @ idx LEFT RIGHT * inserted at idx + 1 */ temp = new->br_startoff - PREV.br_startoff; temp2 = PREV.br_startoff + PREV.br_blockcount - new_endoff; trace_xfs_bmap_pre_update(bma->ip, bma->idx, 0, _THIS_IP_); xfs_bmbt_set_blockcount(ep, temp); /* truncate PREV */ LEFT = *new; RIGHT.br_state = PREV.br_state; RIGHT.br_startblock = nullstartblock( (int)xfs_bmap_worst_indlen(bma->ip, temp2)); RIGHT.br_startoff = new_endoff; RIGHT.br_blockcount = temp2; /* insert LEFT (r[0]) and RIGHT (r[1]) at the same time */ xfs_iext_insert(bma->ip, bma->idx + 1, 2, &LEFT, state); bma->ip->i_d.di_nextents++; if (bma->cur == NULL) rval = XFS_ILOG_CORE | XFS_ILOG_DEXT; else { rval = XFS_ILOG_CORE; error = xfs_bmbt_lookup_eq(bma->cur, new->br_startoff, new->br_startblock, new->br_blockcount, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 0, done); bma->cur->bc_rec.b.br_state = XFS_EXT_NORM; error = xfs_btree_insert(bma->cur, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); } if (xfs_bmap_needs_btree(bma->ip, XFS_DATA_FORK)) { error = xfs_bmap_extents_to_btree(bma->tp, bma->ip, bma->firstblock, bma->flist, &bma->cur, 1, &tmp_rval, XFS_DATA_FORK); rval |= tmp_rval; if (error) goto done; } temp = xfs_bmap_worst_indlen(bma->ip, temp); temp2 = xfs_bmap_worst_indlen(bma->ip, temp2); diff = (int)(temp + temp2 - startblockval(PREV.br_startblock) - (bma->cur ? bma->cur->bc_private.b.allocated : 0)); if (diff > 0) { error = xfs_mod_fdblocks(bma->ip->i_mount, -((int64_t)diff), false); ASSERT(!error); if (error) goto done; } ep = xfs_iext_get_ext(ifp, bma->idx); xfs_bmbt_set_startblock(ep, nullstartblock((int)temp)); trace_xfs_bmap_post_update(bma->ip, bma->idx, state, _THIS_IP_); trace_xfs_bmap_pre_update(bma->ip, bma->idx + 2, state, _THIS_IP_); xfs_bmbt_set_startblock(xfs_iext_get_ext(ifp, bma->idx + 2), nullstartblock((int)temp2)); trace_xfs_bmap_post_update(bma->ip, bma->idx + 2, state, _THIS_IP_); bma->idx++; da_new = temp + temp2; break; case BMAP_LEFT_FILLING | BMAP_LEFT_CONTIG | BMAP_RIGHT_CONTIG: case BMAP_RIGHT_FILLING | BMAP_LEFT_CONTIG | BMAP_RIGHT_CONTIG: case BMAP_LEFT_FILLING | BMAP_RIGHT_CONTIG: case BMAP_RIGHT_FILLING | BMAP_LEFT_CONTIG: case BMAP_LEFT_CONTIG | BMAP_RIGHT_CONTIG: case BMAP_LEFT_CONTIG: case BMAP_RIGHT_CONTIG: /* * These cases are all impossible. */ ASSERT(0); } /* convert to a btree if necessary */ if (xfs_bmap_needs_btree(bma->ip, XFS_DATA_FORK)) { int tmp_logflags; /* partial log flag return val */ ASSERT(bma->cur == NULL); error = xfs_bmap_extents_to_btree(bma->tp, bma->ip, bma->firstblock, bma->flist, &bma->cur, da_old > 0, &tmp_logflags, XFS_DATA_FORK); bma->logflags |= tmp_logflags; if (error) goto done; } /* adjust for changes in reserved delayed indirect blocks */ if (da_old || da_new) { temp = da_new; if (bma->cur) temp += bma->cur->bc_private.b.allocated; ASSERT(temp <= da_old); if (temp < da_old) xfs_mod_fdblocks(bma->ip->i_mount, (int64_t)(da_old - temp), false); } /* clear out the allocated field, done with it now in any case. */ if (bma->cur) bma->cur->bc_private.b.allocated = 0; xfs_bmap_check_leaf_extents(bma->cur, bma->ip, XFS_DATA_FORK); done: bma->logflags |= rval; return error; #undef LEFT #undef RIGHT #undef PREV } /* * Convert an unwritten allocation to a real allocation or vice versa. */ STATIC int /* error */ xfs_bmap_add_extent_unwritten_real( struct xfs_trans *tp, xfs_inode_t *ip, /* incore inode pointer */ xfs_extnum_t *idx, /* extent number to update/insert */ xfs_btree_cur_t **curp, /* if *curp is null, not a btree */ xfs_bmbt_irec_t *new, /* new data to add to file extents */ xfs_fsblock_t *first, /* pointer to firstblock variable */ xfs_bmap_free_t *flist, /* list of extents to be freed */ int *logflagsp) /* inode logging flags */ { xfs_btree_cur_t *cur; /* btree cursor */ xfs_bmbt_rec_host_t *ep; /* extent entry for idx */ int error; /* error return value */ int i; /* temp state */ xfs_ifork_t *ifp; /* inode fork pointer */ xfs_fileoff_t new_endoff; /* end offset of new entry */ xfs_exntst_t newext; /* new extent state */ xfs_exntst_t oldext; /* old extent state */ xfs_bmbt_irec_t r[3]; /* neighbor extent entries */ /* left is 0, right is 1, prev is 2 */ int rval=0; /* return value (logging flags) */ int state = 0;/* state bits, accessed thru macros */ struct xfs_mount *mp = tp->t_mountp; *logflagsp = 0; cur = *curp; ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK); ASSERT(*idx >= 0); ASSERT(*idx <= ifp->if_bytes / sizeof(struct xfs_bmbt_rec)); ASSERT(!isnullstartblock(new->br_startblock)); XFS_STATS_INC(xs_add_exlist); #define LEFT r[0] #define RIGHT r[1] #define PREV r[2] /* * Set up a bunch of variables to make the tests simpler. */ error = 0; ep = xfs_iext_get_ext(ifp, *idx); xfs_bmbt_get_all(ep, &PREV); newext = new->br_state; oldext = (newext == XFS_EXT_UNWRITTEN) ? XFS_EXT_NORM : XFS_EXT_UNWRITTEN; ASSERT(PREV.br_state == oldext); new_endoff = new->br_startoff + new->br_blockcount; ASSERT(PREV.br_startoff <= new->br_startoff); ASSERT(PREV.br_startoff + PREV.br_blockcount >= new_endoff); /* * Set flags determining what part of the previous oldext allocation * extent is being replaced by a newext allocation. */ if (PREV.br_startoff == new->br_startoff) state |= BMAP_LEFT_FILLING; if (PREV.br_startoff + PREV.br_blockcount == new_endoff) state |= BMAP_RIGHT_FILLING; /* * Check and set flags if this segment has a left neighbor. * Don't set contiguous if the combined extent would be too large. */ if (*idx > 0) { state |= BMAP_LEFT_VALID; xfs_bmbt_get_all(xfs_iext_get_ext(ifp, *idx - 1), &LEFT); if (isnullstartblock(LEFT.br_startblock)) state |= BMAP_LEFT_DELAY; } if ((state & BMAP_LEFT_VALID) && !(state & BMAP_LEFT_DELAY) && LEFT.br_startoff + LEFT.br_blockcount == new->br_startoff && LEFT.br_startblock + LEFT.br_blockcount == new->br_startblock && LEFT.br_state == newext && LEFT.br_blockcount + new->br_blockcount <= MAXEXTLEN) state |= BMAP_LEFT_CONTIG; /* * Check and set flags if this segment has a right neighbor. * Don't set contiguous if the combined extent would be too large. * Also check for all-three-contiguous being too large. */ if (*idx < ip->i_df.if_bytes / (uint)sizeof(xfs_bmbt_rec_t) - 1) { state |= BMAP_RIGHT_VALID; xfs_bmbt_get_all(xfs_iext_get_ext(ifp, *idx + 1), &RIGHT); if (isnullstartblock(RIGHT.br_startblock)) state |= BMAP_RIGHT_DELAY; } if ((state & BMAP_RIGHT_VALID) && !(state & BMAP_RIGHT_DELAY) && new_endoff == RIGHT.br_startoff && new->br_startblock + new->br_blockcount == RIGHT.br_startblock && newext == RIGHT.br_state && new->br_blockcount + RIGHT.br_blockcount <= MAXEXTLEN && ((state & (BMAP_LEFT_CONTIG | BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING)) != (BMAP_LEFT_CONTIG | BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING) || LEFT.br_blockcount + new->br_blockcount + RIGHT.br_blockcount <= MAXEXTLEN)) state |= BMAP_RIGHT_CONTIG; /* * Switch out based on the FILLING and CONTIG state bits. */ switch (state & (BMAP_LEFT_FILLING | BMAP_LEFT_CONTIG | BMAP_RIGHT_FILLING | BMAP_RIGHT_CONTIG)) { case BMAP_LEFT_FILLING | BMAP_LEFT_CONTIG | BMAP_RIGHT_FILLING | BMAP_RIGHT_CONTIG: /* * Setting all of a previous oldext extent to newext. * The left and right neighbors are both contiguous with new. */ --*idx; trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_); xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, *idx), LEFT.br_blockcount + PREV.br_blockcount + RIGHT.br_blockcount); trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_); xfs_iext_remove(ip, *idx + 1, 2, state); ip->i_d.di_nextents -= 2; if (cur == NULL) rval = XFS_ILOG_CORE | XFS_ILOG_DEXT; else { rval = XFS_ILOG_CORE; if ((error = xfs_bmbt_lookup_eq(cur, RIGHT.br_startoff, RIGHT.br_startblock, RIGHT.br_blockcount, &i))) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); if ((error = xfs_btree_delete(cur, &i))) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); if ((error = xfs_btree_decrement(cur, 0, &i))) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); if ((error = xfs_btree_delete(cur, &i))) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); if ((error = xfs_btree_decrement(cur, 0, &i))) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); if ((error = xfs_bmbt_update(cur, LEFT.br_startoff, LEFT.br_startblock, LEFT.br_blockcount + PREV.br_blockcount + RIGHT.br_blockcount, LEFT.br_state))) goto done; } break; case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING | BMAP_LEFT_CONTIG: /* * Setting all of a previous oldext extent to newext. * The left neighbor is contiguous, the right is not. */ --*idx; trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_); xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, *idx), LEFT.br_blockcount + PREV.br_blockcount); trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_); xfs_iext_remove(ip, *idx + 1, 1, state); ip->i_d.di_nextents--; if (cur == NULL) rval = XFS_ILOG_CORE | XFS_ILOG_DEXT; else { rval = XFS_ILOG_CORE; if ((error = xfs_bmbt_lookup_eq(cur, PREV.br_startoff, PREV.br_startblock, PREV.br_blockcount, &i))) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); if ((error = xfs_btree_delete(cur, &i))) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); if ((error = xfs_btree_decrement(cur, 0, &i))) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); if ((error = xfs_bmbt_update(cur, LEFT.br_startoff, LEFT.br_startblock, LEFT.br_blockcount + PREV.br_blockcount, LEFT.br_state))) goto done; } break; case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING | BMAP_RIGHT_CONTIG: /* * Setting all of a previous oldext extent to newext. * The right neighbor is contiguous, the left is not. */ trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_); xfs_bmbt_set_blockcount(ep, PREV.br_blockcount + RIGHT.br_blockcount); xfs_bmbt_set_state(ep, newext); trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_); xfs_iext_remove(ip, *idx + 1, 1, state); ip->i_d.di_nextents--; if (cur == NULL) rval = XFS_ILOG_CORE | XFS_ILOG_DEXT; else { rval = XFS_ILOG_CORE; if ((error = xfs_bmbt_lookup_eq(cur, RIGHT.br_startoff, RIGHT.br_startblock, RIGHT.br_blockcount, &i))) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); if ((error = xfs_btree_delete(cur, &i))) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); if ((error = xfs_btree_decrement(cur, 0, &i))) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); if ((error = xfs_bmbt_update(cur, new->br_startoff, new->br_startblock, new->br_blockcount + RIGHT.br_blockcount, newext))) goto done; } break; case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING: /* * Setting all of a previous oldext extent to newext. * Neither the left nor right neighbors are contiguous with * the new one. */ trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_); xfs_bmbt_set_state(ep, newext); trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_); if (cur == NULL) rval = XFS_ILOG_DEXT; else { rval = 0; if ((error = xfs_bmbt_lookup_eq(cur, new->br_startoff, new->br_startblock, new->br_blockcount, &i))) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); if ((error = xfs_bmbt_update(cur, new->br_startoff, new->br_startblock, new->br_blockcount, newext))) goto done; } break; case BMAP_LEFT_FILLING | BMAP_LEFT_CONTIG: /* * Setting the first part of a previous oldext extent to newext. * The left neighbor is contiguous. */ trace_xfs_bmap_pre_update(ip, *idx - 1, state, _THIS_IP_); xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, *idx - 1), LEFT.br_blockcount + new->br_blockcount); xfs_bmbt_set_startoff(ep, PREV.br_startoff + new->br_blockcount); trace_xfs_bmap_post_update(ip, *idx - 1, state, _THIS_IP_); trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_); xfs_bmbt_set_startblock(ep, new->br_startblock + new->br_blockcount); xfs_bmbt_set_blockcount(ep, PREV.br_blockcount - new->br_blockcount); trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_); --*idx; if (cur == NULL) rval = XFS_ILOG_DEXT; else { rval = 0; if ((error = xfs_bmbt_lookup_eq(cur, PREV.br_startoff, PREV.br_startblock, PREV.br_blockcount, &i))) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); if ((error = xfs_bmbt_update(cur, PREV.br_startoff + new->br_blockcount, PREV.br_startblock + new->br_blockcount, PREV.br_blockcount - new->br_blockcount, oldext))) goto done; if ((error = xfs_btree_decrement(cur, 0, &i))) goto done; error = xfs_bmbt_update(cur, LEFT.br_startoff, LEFT.br_startblock, LEFT.br_blockcount + new->br_blockcount, LEFT.br_state); if (error) goto done; } break; case BMAP_LEFT_FILLING: /* * Setting the first part of a previous oldext extent to newext. * The left neighbor is not contiguous. */ trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_); ASSERT(ep && xfs_bmbt_get_state(ep) == oldext); xfs_bmbt_set_startoff(ep, new_endoff); xfs_bmbt_set_blockcount(ep, PREV.br_blockcount - new->br_blockcount); xfs_bmbt_set_startblock(ep, new->br_startblock + new->br_blockcount); trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_); xfs_iext_insert(ip, *idx, 1, new, state); ip->i_d.di_nextents++; if (cur == NULL) rval = XFS_ILOG_CORE | XFS_ILOG_DEXT; else { rval = XFS_ILOG_CORE; if ((error = xfs_bmbt_lookup_eq(cur, PREV.br_startoff, PREV.br_startblock, PREV.br_blockcount, &i))) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); if ((error = xfs_bmbt_update(cur, PREV.br_startoff + new->br_blockcount, PREV.br_startblock + new->br_blockcount, PREV.br_blockcount - new->br_blockcount, oldext))) goto done; cur->bc_rec.b = *new; if ((error = xfs_btree_insert(cur, &i))) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); } break; case BMAP_RIGHT_FILLING | BMAP_RIGHT_CONTIG: /* * Setting the last part of a previous oldext extent to newext. * The right neighbor is contiguous with the new allocation. */ trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_); xfs_bmbt_set_blockcount(ep, PREV.br_blockcount - new->br_blockcount); trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_); ++*idx; trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_); xfs_bmbt_set_allf(xfs_iext_get_ext(ifp, *idx), new->br_startoff, new->br_startblock, new->br_blockcount + RIGHT.br_blockcount, newext); trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_); if (cur == NULL) rval = XFS_ILOG_DEXT; else { rval = 0; if ((error = xfs_bmbt_lookup_eq(cur, PREV.br_startoff, PREV.br_startblock, PREV.br_blockcount, &i))) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); if ((error = xfs_bmbt_update(cur, PREV.br_startoff, PREV.br_startblock, PREV.br_blockcount - new->br_blockcount, oldext))) goto done; if ((error = xfs_btree_increment(cur, 0, &i))) goto done; if ((error = xfs_bmbt_update(cur, new->br_startoff, new->br_startblock, new->br_blockcount + RIGHT.br_blockcount, newext))) goto done; } break; case BMAP_RIGHT_FILLING: /* * Setting the last part of a previous oldext extent to newext. * The right neighbor is not contiguous. */ trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_); xfs_bmbt_set_blockcount(ep, PREV.br_blockcount - new->br_blockcount); trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_); ++*idx; xfs_iext_insert(ip, *idx, 1, new, state); ip->i_d.di_nextents++; if (cur == NULL) rval = XFS_ILOG_CORE | XFS_ILOG_DEXT; else { rval = XFS_ILOG_CORE; if ((error = xfs_bmbt_lookup_eq(cur, PREV.br_startoff, PREV.br_startblock, PREV.br_blockcount, &i))) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); if ((error = xfs_bmbt_update(cur, PREV.br_startoff, PREV.br_startblock, PREV.br_blockcount - new->br_blockcount, oldext))) goto done; if ((error = xfs_bmbt_lookup_eq(cur, new->br_startoff, new->br_startblock, new->br_blockcount, &i))) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 0, done); cur->bc_rec.b.br_state = XFS_EXT_NORM; if ((error = xfs_btree_insert(cur, &i))) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); } break; case 0: /* * Setting the middle part of a previous oldext extent to * newext. Contiguity is impossible here. * One extent becomes three extents. */ trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_); xfs_bmbt_set_blockcount(ep, new->br_startoff - PREV.br_startoff); trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_); r[0] = *new; r[1].br_startoff = new_endoff; r[1].br_blockcount = PREV.br_startoff + PREV.br_blockcount - new_endoff; r[1].br_startblock = new->br_startblock + new->br_blockcount; r[1].br_state = oldext; ++*idx; xfs_iext_insert(ip, *idx, 2, &r[0], state); ip->i_d.di_nextents += 2; if (cur == NULL) rval = XFS_ILOG_CORE | XFS_ILOG_DEXT; else { rval = XFS_ILOG_CORE; if ((error = xfs_bmbt_lookup_eq(cur, PREV.br_startoff, PREV.br_startblock, PREV.br_blockcount, &i))) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); /* new right extent - oldext */ if ((error = xfs_bmbt_update(cur, r[1].br_startoff, r[1].br_startblock, r[1].br_blockcount, r[1].br_state))) goto done; /* new left extent - oldext */ cur->bc_rec.b = PREV; cur->bc_rec.b.br_blockcount = new->br_startoff - PREV.br_startoff; if ((error = xfs_btree_insert(cur, &i))) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); /* * Reset the cursor to the position of the new extent * we are about to insert as we can't trust it after * the previous insert. */ if ((error = xfs_bmbt_lookup_eq(cur, new->br_startoff, new->br_startblock, new->br_blockcount, &i))) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 0, done); /* new middle extent - newext */ cur->bc_rec.b.br_state = new->br_state; if ((error = xfs_btree_insert(cur, &i))) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); } break; case BMAP_LEFT_FILLING | BMAP_LEFT_CONTIG | BMAP_RIGHT_CONTIG: case BMAP_RIGHT_FILLING | BMAP_LEFT_CONTIG | BMAP_RIGHT_CONTIG: case BMAP_LEFT_FILLING | BMAP_RIGHT_CONTIG: case BMAP_RIGHT_FILLING | BMAP_LEFT_CONTIG: case BMAP_LEFT_CONTIG | BMAP_RIGHT_CONTIG: case BMAP_LEFT_CONTIG: case BMAP_RIGHT_CONTIG: /* * These cases are all impossible. */ ASSERT(0); } /* convert to a btree if necessary */ if (xfs_bmap_needs_btree(ip, XFS_DATA_FORK)) { int tmp_logflags; /* partial log flag return val */ ASSERT(cur == NULL); error = xfs_bmap_extents_to_btree(tp, ip, first, flist, &cur, 0, &tmp_logflags, XFS_DATA_FORK); *logflagsp |= tmp_logflags; if (error) goto done; } /* clear out the allocated field, done with it now in any case. */ if (cur) { cur->bc_private.b.allocated = 0; *curp = cur; } xfs_bmap_check_leaf_extents(*curp, ip, XFS_DATA_FORK); done: *logflagsp |= rval; return error; #undef LEFT #undef RIGHT #undef PREV } /* * Convert a hole to a delayed allocation. */ STATIC void xfs_bmap_add_extent_hole_delay( xfs_inode_t *ip, /* incore inode pointer */ xfs_extnum_t *idx, /* extent number to update/insert */ xfs_bmbt_irec_t *new) /* new data to add to file extents */ { xfs_ifork_t *ifp; /* inode fork pointer */ xfs_bmbt_irec_t left; /* left neighbor extent entry */ xfs_filblks_t newlen=0; /* new indirect size */ xfs_filblks_t oldlen=0; /* old indirect size */ xfs_bmbt_irec_t right; /* right neighbor extent entry */ int state; /* state bits, accessed thru macros */ xfs_filblks_t temp=0; /* temp for indirect calculations */ ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK); state = 0; ASSERT(isnullstartblock(new->br_startblock)); /* * Check and set flags if this segment has a left neighbor */ if (*idx > 0) { state |= BMAP_LEFT_VALID; xfs_bmbt_get_all(xfs_iext_get_ext(ifp, *idx - 1), &left); if (isnullstartblock(left.br_startblock)) state |= BMAP_LEFT_DELAY; } /* * Check and set flags if the current (right) segment exists. * If it doesn't exist, we're converting the hole at end-of-file. */ if (*idx < ip->i_df.if_bytes / (uint)sizeof(xfs_bmbt_rec_t)) { state |= BMAP_RIGHT_VALID; xfs_bmbt_get_all(xfs_iext_get_ext(ifp, *idx), &right); if (isnullstartblock(right.br_startblock)) state |= BMAP_RIGHT_DELAY; } /* * Set contiguity flags on the left and right neighbors. * Don't let extents get too large, even if the pieces are contiguous. */ if ((state & BMAP_LEFT_VALID) && (state & BMAP_LEFT_DELAY) && left.br_startoff + left.br_blockcount == new->br_startoff && left.br_blockcount + new->br_blockcount <= MAXEXTLEN) state |= BMAP_LEFT_CONTIG; if ((state & BMAP_RIGHT_VALID) && (state & BMAP_RIGHT_DELAY) && new->br_startoff + new->br_blockcount == right.br_startoff && new->br_blockcount + right.br_blockcount <= MAXEXTLEN && (!(state & BMAP_LEFT_CONTIG) || (left.br_blockcount + new->br_blockcount + right.br_blockcount <= MAXEXTLEN))) state |= BMAP_RIGHT_CONTIG; /* * Switch out based on the contiguity flags. */ switch (state & (BMAP_LEFT_CONTIG | BMAP_RIGHT_CONTIG)) { case BMAP_LEFT_CONTIG | BMAP_RIGHT_CONTIG: /* * New allocation is contiguous with delayed allocations * on the left and on the right. * Merge all three into a single extent record. */ --*idx; temp = left.br_blockcount + new->br_blockcount + right.br_blockcount; trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_); xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, *idx), temp); oldlen = startblockval(left.br_startblock) + startblockval(new->br_startblock) + startblockval(right.br_startblock); newlen = xfs_bmap_worst_indlen(ip, temp); xfs_bmbt_set_startblock(xfs_iext_get_ext(ifp, *idx), nullstartblock((int)newlen)); trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_); xfs_iext_remove(ip, *idx + 1, 1, state); break; case BMAP_LEFT_CONTIG: /* * New allocation is contiguous with a delayed allocation * on the left. * Merge the new allocation with the left neighbor. */ --*idx; temp = left.br_blockcount + new->br_blockcount; trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_); xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, *idx), temp); oldlen = startblockval(left.br_startblock) + startblockval(new->br_startblock); newlen = xfs_bmap_worst_indlen(ip, temp); xfs_bmbt_set_startblock(xfs_iext_get_ext(ifp, *idx), nullstartblock((int)newlen)); trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_); break; case BMAP_RIGHT_CONTIG: /* * New allocation is contiguous with a delayed allocation * on the right. * Merge the new allocation with the right neighbor. */ trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_); temp = new->br_blockcount + right.br_blockcount; oldlen = startblockval(new->br_startblock) + startblockval(right.br_startblock); newlen = xfs_bmap_worst_indlen(ip, temp); xfs_bmbt_set_allf(xfs_iext_get_ext(ifp, *idx), new->br_startoff, nullstartblock((int)newlen), temp, right.br_state); trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_); break; case 0: /* * New allocation is not contiguous with another * delayed allocation. * Insert a new entry. */ oldlen = newlen = 0; xfs_iext_insert(ip, *idx, 1, new, state); break; } if (oldlen != newlen) { ASSERT(oldlen > newlen); xfs_mod_fdblocks(ip->i_mount, (int64_t)(oldlen - newlen), false); /* * Nothing to do for disk quota accounting here. */ } } /* * Convert a hole to a real allocation. */ STATIC int /* error */ xfs_bmap_add_extent_hole_real( struct xfs_bmalloca *bma, int whichfork) { struct xfs_bmbt_irec *new = &bma->got; int error; /* error return value */ int i; /* temp state */ xfs_ifork_t *ifp; /* inode fork pointer */ xfs_bmbt_irec_t left; /* left neighbor extent entry */ xfs_bmbt_irec_t right; /* right neighbor extent entry */ int rval=0; /* return value (logging flags) */ int state; /* state bits, accessed thru macros */ struct xfs_mount *mp; mp = bma->tp ? bma->tp->t_mountp : NULL; ifp = XFS_IFORK_PTR(bma->ip, whichfork); ASSERT(bma->idx >= 0); ASSERT(bma->idx <= ifp->if_bytes / sizeof(struct xfs_bmbt_rec)); ASSERT(!isnullstartblock(new->br_startblock)); ASSERT(!bma->cur || !(bma->cur->bc_private.b.flags & XFS_BTCUR_BPRV_WASDEL)); XFS_STATS_INC(xs_add_exlist); state = 0; if (whichfork == XFS_ATTR_FORK) state |= BMAP_ATTRFORK; /* * Check and set flags if this segment has a left neighbor. */ if (bma->idx > 0) { state |= BMAP_LEFT_VALID; xfs_bmbt_get_all(xfs_iext_get_ext(ifp, bma->idx - 1), &left); if (isnullstartblock(left.br_startblock)) state |= BMAP_LEFT_DELAY; } /* * Check and set flags if this segment has a current value. * Not true if we're inserting into the "hole" at eof. */ if (bma->idx < ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t)) { state |= BMAP_RIGHT_VALID; xfs_bmbt_get_all(xfs_iext_get_ext(ifp, bma->idx), &right); if (isnullstartblock(right.br_startblock)) state |= BMAP_RIGHT_DELAY; } /* * We're inserting a real allocation between "left" and "right". * Set the contiguity flags. Don't let extents get too large. */ if ((state & BMAP_LEFT_VALID) && !(state & BMAP_LEFT_DELAY) && left.br_startoff + left.br_blockcount == new->br_startoff && left.br_startblock + left.br_blockcount == new->br_startblock && left.br_state == new->br_state && left.br_blockcount + new->br_blockcount <= MAXEXTLEN) state |= BMAP_LEFT_CONTIG; if ((state & BMAP_RIGHT_VALID) && !(state & BMAP_RIGHT_DELAY) && new->br_startoff + new->br_blockcount == right.br_startoff && new->br_startblock + new->br_blockcount == right.br_startblock && new->br_state == right.br_state && new->br_blockcount + right.br_blockcount <= MAXEXTLEN && (!(state & BMAP_LEFT_CONTIG) || left.br_blockcount + new->br_blockcount + right.br_blockcount <= MAXEXTLEN)) state |= BMAP_RIGHT_CONTIG; error = 0; /* * Select which case we're in here, and implement it. */ switch (state & (BMAP_LEFT_CONTIG | BMAP_RIGHT_CONTIG)) { case BMAP_LEFT_CONTIG | BMAP_RIGHT_CONTIG: /* * New allocation is contiguous with real allocations on the * left and on the right. * Merge all three into a single extent record. */ --bma->idx; trace_xfs_bmap_pre_update(bma->ip, bma->idx, state, _THIS_IP_); xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, bma->idx), left.br_blockcount + new->br_blockcount + right.br_blockcount); trace_xfs_bmap_post_update(bma->ip, bma->idx, state, _THIS_IP_); xfs_iext_remove(bma->ip, bma->idx + 1, 1, state); XFS_IFORK_NEXT_SET(bma->ip, whichfork, XFS_IFORK_NEXTENTS(bma->ip, whichfork) - 1); if (bma->cur == NULL) { rval = XFS_ILOG_CORE | xfs_ilog_fext(whichfork); } else { rval = XFS_ILOG_CORE; error = xfs_bmbt_lookup_eq(bma->cur, right.br_startoff, right.br_startblock, right.br_blockcount, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); error = xfs_btree_delete(bma->cur, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); error = xfs_btree_decrement(bma->cur, 0, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); error = xfs_bmbt_update(bma->cur, left.br_startoff, left.br_startblock, left.br_blockcount + new->br_blockcount + right.br_blockcount, left.br_state); if (error) goto done; } break; case BMAP_LEFT_CONTIG: /* * New allocation is contiguous with a real allocation * on the left. * Merge the new allocation with the left neighbor. */ --bma->idx; trace_xfs_bmap_pre_update(bma->ip, bma->idx, state, _THIS_IP_); xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, bma->idx), left.br_blockcount + new->br_blockcount); trace_xfs_bmap_post_update(bma->ip, bma->idx, state, _THIS_IP_); if (bma->cur == NULL) { rval = xfs_ilog_fext(whichfork); } else { rval = 0; error = xfs_bmbt_lookup_eq(bma->cur, left.br_startoff, left.br_startblock, left.br_blockcount, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); error = xfs_bmbt_update(bma->cur, left.br_startoff, left.br_startblock, left.br_blockcount + new->br_blockcount, left.br_state); if (error) goto done; } break; case BMAP_RIGHT_CONTIG: /* * New allocation is contiguous with a real allocation * on the right. * Merge the new allocation with the right neighbor. */ trace_xfs_bmap_pre_update(bma->ip, bma->idx, state, _THIS_IP_); xfs_bmbt_set_allf(xfs_iext_get_ext(ifp, bma->idx), new->br_startoff, new->br_startblock, new->br_blockcount + right.br_blockcount, right.br_state); trace_xfs_bmap_post_update(bma->ip, bma->idx, state, _THIS_IP_); if (bma->cur == NULL) { rval = xfs_ilog_fext(whichfork); } else { rval = 0; error = xfs_bmbt_lookup_eq(bma->cur, right.br_startoff, right.br_startblock, right.br_blockcount, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); error = xfs_bmbt_update(bma->cur, new->br_startoff, new->br_startblock, new->br_blockcount + right.br_blockcount, right.br_state); if (error) goto done; } break; case 0: /* * New allocation is not contiguous with another * real allocation. * Insert a new entry. */ xfs_iext_insert(bma->ip, bma->idx, 1, new, state); XFS_IFORK_NEXT_SET(bma->ip, whichfork, XFS_IFORK_NEXTENTS(bma->ip, whichfork) + 1); if (bma->cur == NULL) { rval = XFS_ILOG_CORE | xfs_ilog_fext(whichfork); } else { rval = XFS_ILOG_CORE; error = xfs_bmbt_lookup_eq(bma->cur, new->br_startoff, new->br_startblock, new->br_blockcount, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 0, done); bma->cur->bc_rec.b.br_state = new->br_state; error = xfs_btree_insert(bma->cur, &i); if (error) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); } break; } /* convert to a btree if necessary */ if (xfs_bmap_needs_btree(bma->ip, whichfork)) { int tmp_logflags; /* partial log flag return val */ ASSERT(bma->cur == NULL); error = xfs_bmap_extents_to_btree(bma->tp, bma->ip, bma->firstblock, bma->flist, &bma->cur, 0, &tmp_logflags, whichfork); bma->logflags |= tmp_logflags; if (error) goto done; } /* clear out the allocated field, done with it now in any case. */ if (bma->cur) bma->cur->bc_private.b.allocated = 0; xfs_bmap_check_leaf_extents(bma->cur, bma->ip, whichfork); done: bma->logflags |= rval; return error; } /* * Functions used in the extent read, allocate and remove paths */ /* * Adjust the size of the new extent based on di_extsize and rt extsize. */ int xfs_bmap_extsize_align( xfs_mount_t *mp, xfs_bmbt_irec_t *gotp, /* next extent pointer */ xfs_bmbt_irec_t *prevp, /* previous extent pointer */ xfs_extlen_t extsz, /* align to this extent size */ int rt, /* is this a realtime inode? */ int eof, /* is extent at end-of-file? */ int delay, /* creating delalloc extent? */ int convert, /* overwriting unwritten extent? */ xfs_fileoff_t *offp, /* in/out: aligned offset */ xfs_extlen_t *lenp) /* in/out: aligned length */ { xfs_fileoff_t orig_off; /* original offset */ xfs_extlen_t orig_alen; /* original length */ xfs_fileoff_t orig_end; /* original off+len */ xfs_fileoff_t nexto; /* next file offset */ xfs_fileoff_t prevo; /* previous file offset */ xfs_fileoff_t align_off; /* temp for offset */ xfs_extlen_t align_alen; /* temp for length */ xfs_extlen_t temp; /* temp for calculations */ if (convert) return 0; orig_off = align_off = *offp; orig_alen = align_alen = *lenp; orig_end = orig_off + orig_alen; /* * If this request overlaps an existing extent, then don't * attempt to perform any additional alignment. */ if (!delay && !eof && (orig_off >= gotp->br_startoff) && (orig_end <= gotp->br_startoff + gotp->br_blockcount)) { return 0; } /* * If the file offset is unaligned vs. the extent size * we need to align it. This will be possible unless * the file was previously written with a kernel that didn't * perform this alignment, or if a truncate shot us in the * foot. */ temp = do_mod(orig_off, extsz); if (temp) { align_alen += temp; align_off -= temp; } /* Same adjustment for the end of the requested area. */ temp = (align_alen % extsz); if (temp) align_alen += extsz - temp; /* * For large extent hint sizes, the aligned extent might be larger than * MAXEXTLEN. In that case, reduce the size by an extsz so that it pulls * the length back under MAXEXTLEN. The outer allocation loops handle * short allocation just fine, so it is safe to do this. We only want to * do it when we are forced to, though, because it means more allocation * operations are required. */ while (align_alen > MAXEXTLEN) align_alen -= extsz; ASSERT(align_alen <= MAXEXTLEN); /* * If the previous block overlaps with this proposed allocation * then move the start forward without adjusting the length. */ if (prevp->br_startoff != NULLFILEOFF) { if (prevp->br_startblock == HOLESTARTBLOCK) prevo = prevp->br_startoff; else prevo = prevp->br_startoff + prevp->br_blockcount; } else prevo = 0; if (align_off != orig_off && align_off < prevo) align_off = prevo; /* * If the next block overlaps with this proposed allocation * then move the start back without adjusting the length, * but not before offset 0. * This may of course make the start overlap previous block, * and if we hit the offset 0 limit then the next block * can still overlap too. */ if (!eof && gotp->br_startoff != NULLFILEOFF) { if ((delay && gotp->br_startblock == HOLESTARTBLOCK) || (!delay && gotp->br_startblock == DELAYSTARTBLOCK)) nexto = gotp->br_startoff + gotp->br_blockcount; else nexto = gotp->br_startoff; } else nexto = NULLFILEOFF; if (!eof && align_off + align_alen != orig_end && align_off + align_alen > nexto) align_off = nexto > align_alen ? nexto - align_alen : 0; /* * If we're now overlapping the next or previous extent that * means we can't fit an extsz piece in this hole. Just move * the start forward to the first valid spot and set * the length so we hit the end. */ if (align_off != orig_off && align_off < prevo) align_off = prevo; if (align_off + align_alen != orig_end && align_off + align_alen > nexto && nexto != NULLFILEOFF) { ASSERT(nexto > prevo); align_alen = nexto - align_off; } /* * If realtime, and the result isn't a multiple of the realtime * extent size we need to remove blocks until it is. */ if (rt && (temp = (align_alen % mp->m_sb.sb_rextsize))) { /* * We're not covering the original request, or * we won't be able to once we fix the length. */ if (orig_off < align_off || orig_end > align_off + align_alen || align_alen - temp < orig_alen) return -EINVAL; /* * Try to fix it by moving the start up. */ if (align_off + temp <= orig_off) { align_alen -= temp; align_off += temp; } /* * Try to fix it by moving the end in. */ else if (align_off + align_alen - temp >= orig_end) align_alen -= temp; /* * Set the start to the minimum then trim the length. */ else { align_alen -= orig_off - align_off; align_off = orig_off; align_alen -= align_alen % mp->m_sb.sb_rextsize; } /* * Result doesn't cover the request, fail it. */ if (orig_off < align_off || orig_end > align_off + align_alen) return -EINVAL; } else { ASSERT(orig_off >= align_off); /* see MAXEXTLEN handling above */ ASSERT(orig_end <= align_off + align_alen || align_alen + extsz > MAXEXTLEN); } #ifdef DEBUG if (!eof && gotp->br_startoff != NULLFILEOFF) ASSERT(align_off + align_alen <= gotp->br_startoff); if (prevp->br_startoff != NULLFILEOFF) ASSERT(align_off >= prevp->br_startoff + prevp->br_blockcount); #endif *lenp = align_alen; *offp = align_off; return 0; } #define XFS_ALLOC_GAP_UNITS 4 void xfs_bmap_adjacent( struct xfs_bmalloca *ap) /* bmap alloc argument struct */ { xfs_fsblock_t adjust; /* adjustment to block numbers */ xfs_agnumber_t fb_agno; /* ag number of ap->firstblock */ xfs_mount_t *mp; /* mount point structure */ int nullfb; /* true if ap->firstblock isn't set */ int rt; /* true if inode is realtime */ #define ISVALID(x,y) \ (rt ? \ (x) < mp->m_sb.sb_rblocks : \ XFS_FSB_TO_AGNO(mp, x) == XFS_FSB_TO_AGNO(mp, y) && \ XFS_FSB_TO_AGNO(mp, x) < mp->m_sb.sb_agcount && \ XFS_FSB_TO_AGBNO(mp, x) < mp->m_sb.sb_agblocks) mp = ap->ip->i_mount; nullfb = *ap->firstblock == NULLFSBLOCK; rt = XFS_IS_REALTIME_INODE(ap->ip) && ap->userdata; fb_agno = nullfb ? NULLAGNUMBER : XFS_FSB_TO_AGNO(mp, *ap->firstblock); /* * If allocating at eof, and there's a previous real block, * try to use its last block as our starting point. */ if (ap->eof && ap->prev.br_startoff != NULLFILEOFF && !isnullstartblock(ap->prev.br_startblock) && ISVALID(ap->prev.br_startblock + ap->prev.br_blockcount, ap->prev.br_startblock)) { ap->blkno = ap->prev.br_startblock + ap->prev.br_blockcount; /* * Adjust for the gap between prevp and us. */ adjust = ap->offset - (ap->prev.br_startoff + ap->prev.br_blockcount); if (adjust && ISVALID(ap->blkno + adjust, ap->prev.br_startblock)) ap->blkno += adjust; } /* * If not at eof, then compare the two neighbor blocks. * Figure out whether either one gives us a good starting point, * and pick the better one. */ else if (!ap->eof) { xfs_fsblock_t gotbno; /* right side block number */ xfs_fsblock_t gotdiff=0; /* right side difference */ xfs_fsblock_t prevbno; /* left side block number */ xfs_fsblock_t prevdiff=0; /* left side difference */ /* * If there's a previous (left) block, select a requested * start block based on it. */ if (ap->prev.br_startoff != NULLFILEOFF && !isnullstartblock(ap->prev.br_startblock) && (prevbno = ap->prev.br_startblock + ap->prev.br_blockcount) && ISVALID(prevbno, ap->prev.br_startblock)) { /* * Calculate gap to end of previous block. */ adjust = prevdiff = ap->offset - (ap->prev.br_startoff + ap->prev.br_blockcount); /* * Figure the startblock based on the previous block's * end and the gap size. * Heuristic! * If the gap is large relative to the piece we're * allocating, or using it gives us an invalid block * number, then just use the end of the previous block. */ if (prevdiff <= XFS_ALLOC_GAP_UNITS * ap->length && ISVALID(prevbno + prevdiff, ap->prev.br_startblock)) prevbno += adjust; else prevdiff += adjust; /* * If the firstblock forbids it, can't use it, * must use default. */ if (!rt && !nullfb && XFS_FSB_TO_AGNO(mp, prevbno) != fb_agno) prevbno = NULLFSBLOCK; } /* * No previous block or can't follow it, just default. */ else prevbno = NULLFSBLOCK; /* * If there's a following (right) block, select a requested * start block based on it. */ if (!isnullstartblock(ap->got.br_startblock)) { /* * Calculate gap to start of next block. */ adjust = gotdiff = ap->got.br_startoff - ap->offset; /* * Figure the startblock based on the next block's * start and the gap size. */ gotbno = ap->got.br_startblock; /* * Heuristic! * If the gap is large relative to the piece we're * allocating, or using it gives us an invalid block * number, then just use the start of the next block * offset by our length. */ if (gotdiff <= XFS_ALLOC_GAP_UNITS * ap->length && ISVALID(gotbno - gotdiff, gotbno)) gotbno -= adjust; else if (ISVALID(gotbno - ap->length, gotbno)) { gotbno -= ap->length; gotdiff += adjust - ap->length; } else gotdiff += adjust; /* * If the firstblock forbids it, can't use it, * must use default. */ if (!rt && !nullfb && XFS_FSB_TO_AGNO(mp, gotbno) != fb_agno) gotbno = NULLFSBLOCK; } /* * No next block, just default. */ else gotbno = NULLFSBLOCK; /* * If both valid, pick the better one, else the only good * one, else ap->blkno is already set (to 0 or the inode block). */ if (prevbno != NULLFSBLOCK && gotbno != NULLFSBLOCK) ap->blkno = prevdiff <= gotdiff ? prevbno : gotbno; else if (prevbno != NULLFSBLOCK) ap->blkno = prevbno; else if (gotbno != NULLFSBLOCK) ap->blkno = gotbno; } #undef ISVALID } static int xfs_bmap_longest_free_extent( struct xfs_trans *tp, xfs_agnumber_t ag, xfs_extlen_t *blen, int *notinit) { struct xfs_mount *mp = tp->t_mountp; struct xfs_perag *pag; xfs_extlen_t longest; int error = 0; pag = xfs_perag_get(mp, ag); if (!pag->pagf_init) { error = xfs_alloc_pagf_init(mp, tp, ag, XFS_ALLOC_FLAG_TRYLOCK); if (error) goto out; if (!pag->pagf_init) { *notinit = 1; goto out; } } longest = xfs_alloc_longest_free_extent(mp, pag, xfs_alloc_min_freelist(mp, pag)); if (*blen < longest) *blen = longest; out: xfs_perag_put(pag); return error; } static void xfs_bmap_select_minlen( struct xfs_bmalloca *ap, struct xfs_alloc_arg *args, xfs_extlen_t *blen, int notinit) { if (notinit || *blen < ap->minlen) { /* * Since we did a BUF_TRYLOCK above, it is possible that * there is space for this request. */ args->minlen = ap->minlen; } else if (*blen < args->maxlen) { /* * If the best seen length is less than the request length, * use the best as the minimum. */ args->minlen = *blen; } else { /* * Otherwise we've seen an extent as big as maxlen, use that * as the minimum. */ args->minlen = args->maxlen; } } STATIC int xfs_bmap_btalloc_nullfb( struct xfs_bmalloca *ap, struct xfs_alloc_arg *args, xfs_extlen_t *blen) { struct xfs_mount *mp = ap->ip->i_mount; xfs_agnumber_t ag, startag; int notinit = 0; int error; args->type = XFS_ALLOCTYPE_START_BNO; args->total = ap->total; startag = ag = XFS_FSB_TO_AGNO(mp, args->fsbno); if (startag == NULLAGNUMBER) startag = ag = 0; while (*blen < args->maxlen) { error = xfs_bmap_longest_free_extent(args->tp, ag, blen, ¬init); if (error) return error; if (++ag == mp->m_sb.sb_agcount) ag = 0; if (ag == startag) break; } xfs_bmap_select_minlen(ap, args, blen, notinit); return 0; } STATIC int xfs_bmap_btalloc_filestreams( struct xfs_bmalloca *ap, struct xfs_alloc_arg *args, xfs_extlen_t *blen) { struct xfs_mount *mp = ap->ip->i_mount; xfs_agnumber_t ag; int notinit = 0; int error; args->type = XFS_ALLOCTYPE_NEAR_BNO; args->total = ap->total; ag = XFS_FSB_TO_AGNO(mp, args->fsbno); if (ag == NULLAGNUMBER) ag = 0; error = xfs_bmap_longest_free_extent(args->tp, ag, blen, ¬init); if (error) return error; if (*blen < args->maxlen) { error = xfs_filestream_new_ag(ap, &ag); if (error) return error; error = xfs_bmap_longest_free_extent(args->tp, ag, blen, ¬init); if (error) return error; } xfs_bmap_select_minlen(ap, args, blen, notinit); /* * Set the failure fallback case to look in the selected AG as stream * may have moved. */ ap->blkno = args->fsbno = XFS_AGB_TO_FSB(mp, ag, 0); return 0; } STATIC int xfs_bmap_btalloc( struct xfs_bmalloca *ap) /* bmap alloc argument struct */ { xfs_mount_t *mp; /* mount point structure */ xfs_alloctype_t atype = 0; /* type for allocation routines */ xfs_extlen_t align; /* minimum allocation alignment */ xfs_agnumber_t fb_agno; /* ag number of ap->firstblock */ xfs_agnumber_t ag; xfs_alloc_arg_t args; xfs_extlen_t blen; xfs_extlen_t nextminlen = 0; int nullfb; /* true if ap->firstblock isn't set */ int isaligned; int tryagain; int error; int stripe_align; ASSERT(ap->length); mp = ap->ip->i_mount; /* stripe alignment for allocation is determined by mount parameters */ stripe_align = 0; if (mp->m_swidth && (mp->m_flags & XFS_MOUNT_SWALLOC)) stripe_align = mp->m_swidth; else if (mp->m_dalign) stripe_align = mp->m_dalign; align = ap->userdata ? xfs_get_extsz_hint(ap->ip) : 0; if (unlikely(align)) { error = xfs_bmap_extsize_align(mp, &ap->got, &ap->prev, align, 0, ap->eof, 0, ap->conv, &ap->offset, &ap->length); ASSERT(!error); ASSERT(ap->length); } nullfb = *ap->firstblock == NULLFSBLOCK; fb_agno = nullfb ? NULLAGNUMBER : XFS_FSB_TO_AGNO(mp, *ap->firstblock); if (nullfb) { if (ap->userdata && xfs_inode_is_filestream(ap->ip)) { ag = xfs_filestream_lookup_ag(ap->ip); ag = (ag != NULLAGNUMBER) ? ag : 0; ap->blkno = XFS_AGB_TO_FSB(mp, ag, 0); } else { ap->blkno = XFS_INO_TO_FSB(mp, ap->ip->i_ino); } } else ap->blkno = *ap->firstblock; xfs_bmap_adjacent(ap); /* * If allowed, use ap->blkno; otherwise must use firstblock since * it's in the right allocation group. */ if (nullfb || XFS_FSB_TO_AGNO(mp, ap->blkno) == fb_agno) ; else ap->blkno = *ap->firstblock; /* * Normal allocation, done through xfs_alloc_vextent. */ tryagain = isaligned = 0; memset(&args, 0, sizeof(args)); args.tp = ap->tp; args.mp = mp; args.fsbno = ap->blkno; /* Trim the allocation back to the maximum an AG can fit. */ args.maxlen = MIN(ap->length, XFS_ALLOC_AG_MAX_USABLE(mp)); args.firstblock = *ap->firstblock; blen = 0; if (nullfb) { /* * Search for an allocation group with a single extent large * enough for the request. If one isn't found, then adjust * the minimum allocation size to the largest space found. */ if (ap->userdata && xfs_inode_is_filestream(ap->ip)) error = xfs_bmap_btalloc_filestreams(ap, &args, &blen); else error = xfs_bmap_btalloc_nullfb(ap, &args, &blen); if (error) return error; } else if (ap->flist->xbf_low) { if (xfs_inode_is_filestream(ap->ip)) args.type = XFS_ALLOCTYPE_FIRST_AG; else args.type = XFS_ALLOCTYPE_START_BNO; args.total = args.minlen = ap->minlen; } else { args.type = XFS_ALLOCTYPE_NEAR_BNO; args.total = ap->total; args.minlen = ap->minlen; } /* apply extent size hints if obtained earlier */ if (unlikely(align)) { args.prod = align; if ((args.mod = (xfs_extlen_t)do_mod(ap->offset, args.prod))) args.mod = (xfs_extlen_t)(args.prod - args.mod); } else if (mp->m_sb.sb_blocksize >= PAGE_CACHE_SIZE) { args.prod = 1; args.mod = 0; } else { args.prod = PAGE_CACHE_SIZE >> mp->m_sb.sb_blocklog; if ((args.mod = (xfs_extlen_t)(do_mod(ap->offset, args.prod)))) args.mod = (xfs_extlen_t)(args.prod - args.mod); } /* * If we are not low on available data blocks, and the * underlying logical volume manager is a stripe, and * the file offset is zero then try to allocate data * blocks on stripe unit boundary. * NOTE: ap->aeof is only set if the allocation length * is >= the stripe unit and the allocation offset is * at the end of file. */ if (!ap->flist->xbf_low && ap->aeof) { if (!ap->offset) { args.alignment = stripe_align; atype = args.type; isaligned = 1; /* * Adjust for alignment */ if (blen > args.alignment && blen <= args.maxlen) args.minlen = blen - args.alignment; args.minalignslop = 0; } else { /* * First try an exact bno allocation. * If it fails then do a near or start bno * allocation with alignment turned on. */ atype = args.type; tryagain = 1; args.type = XFS_ALLOCTYPE_THIS_BNO; args.alignment = 1; /* * Compute the minlen+alignment for the * next case. Set slop so that the value * of minlen+alignment+slop doesn't go up * between the calls. */ if (blen > stripe_align && blen <= args.maxlen) nextminlen = blen - stripe_align; else nextminlen = args.minlen; if (nextminlen + stripe_align > args.minlen + 1) args.minalignslop = nextminlen + stripe_align - args.minlen - 1; else args.minalignslop = 0; } } else { args.alignment = 1; args.minalignslop = 0; } args.minleft = ap->minleft; args.wasdel = ap->wasdel; args.isfl = 0; args.userdata = ap->userdata; if ((error = xfs_alloc_vextent(&args))) return error; if (tryagain && args.fsbno == NULLFSBLOCK) { /* * Exact allocation failed. Now try with alignment * turned on. */ args.type = atype; args.fsbno = ap->blkno; args.alignment = stripe_align; args.minlen = nextminlen; args.minalignslop = 0; isaligned = 1; if ((error = xfs_alloc_vextent(&args))) return error; } if (isaligned && args.fsbno == NULLFSBLOCK) { /* * allocation failed, so turn off alignment and * try again. */ args.type = atype; args.fsbno = ap->blkno; args.alignment = 0; if ((error = xfs_alloc_vextent(&args))) return error; } if (args.fsbno == NULLFSBLOCK && nullfb && args.minlen > ap->minlen) { args.minlen = ap->minlen; args.type = XFS_ALLOCTYPE_START_BNO; args.fsbno = ap->blkno; if ((error = xfs_alloc_vextent(&args))) return error; } if (args.fsbno == NULLFSBLOCK && nullfb) { args.fsbno = 0; args.type = XFS_ALLOCTYPE_FIRST_AG; args.total = ap->minlen; args.minleft = 0; if ((error = xfs_alloc_vextent(&args))) return error; ap->flist->xbf_low = 1; } if (args.fsbno != NULLFSBLOCK) { /* * check the allocation happened at the same or higher AG than * the first block that was allocated. */ ASSERT(*ap->firstblock == NULLFSBLOCK || XFS_FSB_TO_AGNO(mp, *ap->firstblock) == XFS_FSB_TO_AGNO(mp, args.fsbno) || (ap->flist->xbf_low && XFS_FSB_TO_AGNO(mp, *ap->firstblock) < XFS_FSB_TO_AGNO(mp, args.fsbno))); ap->blkno = args.fsbno; if (*ap->firstblock == NULLFSBLOCK) *ap->firstblock = args.fsbno; ASSERT(nullfb || fb_agno == args.agno || (ap->flist->xbf_low && fb_agno < args.agno)); ap->length = args.len; ap->ip->i_d.di_nblocks += args.len; xfs_trans_log_inode(ap->tp, ap->ip, XFS_ILOG_CORE); if (ap->wasdel) ap->ip->i_delayed_blks -= args.len; /* * Adjust the disk quota also. This was reserved * earlier. */ xfs_trans_mod_dquot_byino(ap->tp, ap->ip, ap->wasdel ? XFS_TRANS_DQ_DELBCOUNT : XFS_TRANS_DQ_BCOUNT, (long) args.len); } else { ap->blkno = NULLFSBLOCK; ap->length = 0; } return 0; } /* * xfs_bmap_alloc is called by xfs_bmapi to allocate an extent for a file. * It figures out where to ask the underlying allocator to put the new extent. */ STATIC int xfs_bmap_alloc( struct xfs_bmalloca *ap) /* bmap alloc argument struct */ { if (XFS_IS_REALTIME_INODE(ap->ip) && ap->userdata) return xfs_bmap_rtalloc(ap); return xfs_bmap_btalloc(ap); } /* * Trim the returned map to the required bounds */ STATIC void xfs_bmapi_trim_map( struct xfs_bmbt_irec *mval, struct xfs_bmbt_irec *got, xfs_fileoff_t *bno, xfs_filblks_t len, xfs_fileoff_t obno, xfs_fileoff_t end, int n, int flags) { if ((flags & XFS_BMAPI_ENTIRE) || got->br_startoff + got->br_blockcount <= obno) { *mval = *got; if (isnullstartblock(got->br_startblock)) mval->br_startblock = DELAYSTARTBLOCK; return; } if (obno > *bno) *bno = obno; ASSERT((*bno >= obno) || (n == 0)); ASSERT(*bno < end); mval->br_startoff = *bno; if (isnullstartblock(got->br_startblock)) mval->br_startblock = DELAYSTARTBLOCK; else mval->br_startblock = got->br_startblock + (*bno - got->br_startoff); /* * Return the minimum of what we got and what we asked for for * the length. We can use the len variable here because it is * modified below and we could have been there before coming * here if the first part of the allocation didn't overlap what * was asked for. */ mval->br_blockcount = XFS_FILBLKS_MIN(end - *bno, got->br_blockcount - (*bno - got->br_startoff)); mval->br_state = got->br_state; ASSERT(mval->br_blockcount <= len); return; } /* * Update and validate the extent map to return */ STATIC void xfs_bmapi_update_map( struct xfs_bmbt_irec **map, xfs_fileoff_t *bno, xfs_filblks_t *len, xfs_fileoff_t obno, xfs_fileoff_t end, int *n, int flags) { xfs_bmbt_irec_t *mval = *map; ASSERT((flags & XFS_BMAPI_ENTIRE) || ((mval->br_startoff + mval->br_blockcount) <= end)); ASSERT((flags & XFS_BMAPI_ENTIRE) || (mval->br_blockcount <= *len) || (mval->br_startoff < obno)); *bno = mval->br_startoff + mval->br_blockcount; *len = end - *bno; if (*n > 0 && mval->br_startoff == mval[-1].br_startoff) { /* update previous map with new information */ ASSERT(mval->br_startblock == mval[-1].br_startblock); ASSERT(mval->br_blockcount > mval[-1].br_blockcount); ASSERT(mval->br_state == mval[-1].br_state); mval[-1].br_blockcount = mval->br_blockcount; mval[-1].br_state = mval->br_state; } else if (*n > 0 && mval->br_startblock != DELAYSTARTBLOCK && mval[-1].br_startblock != DELAYSTARTBLOCK && mval[-1].br_startblock != HOLESTARTBLOCK && mval->br_startblock == mval[-1].br_startblock + mval[-1].br_blockcount && ((flags & XFS_BMAPI_IGSTATE) || mval[-1].br_state == mval->br_state)) { ASSERT(mval->br_startoff == mval[-1].br_startoff + mval[-1].br_blockcount); mval[-1].br_blockcount += mval->br_blockcount; } else if (*n > 0 && mval->br_startblock == DELAYSTARTBLOCK && mval[-1].br_startblock == DELAYSTARTBLOCK && mval->br_startoff == mval[-1].br_startoff + mval[-1].br_blockcount) { mval[-1].br_blockcount += mval->br_blockcount; mval[-1].br_state = mval->br_state; } else if (!((*n == 0) && ((mval->br_startoff + mval->br_blockcount) <= obno))) { mval++; (*n)++; } *map = mval; } /* * Map file blocks to filesystem blocks without allocation. */ int xfs_bmapi_read( struct xfs_inode *ip, xfs_fileoff_t bno, xfs_filblks_t len, struct xfs_bmbt_irec *mval, int *nmap, int flags) { struct xfs_mount *mp = ip->i_mount; struct xfs_ifork *ifp; struct xfs_bmbt_irec got; struct xfs_bmbt_irec prev; xfs_fileoff_t obno; xfs_fileoff_t end; xfs_extnum_t lastx; int error; int eof; int n = 0; int whichfork = (flags & XFS_BMAPI_ATTRFORK) ? XFS_ATTR_FORK : XFS_DATA_FORK; ASSERT(*nmap >= 1); ASSERT(!(flags & ~(XFS_BMAPI_ATTRFORK|XFS_BMAPI_ENTIRE| XFS_BMAPI_IGSTATE))); ASSERT(xfs_isilocked(ip, XFS_ILOCK_SHARED|XFS_ILOCK_EXCL)); if (unlikely(XFS_TEST_ERROR( (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS && XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE), mp, XFS_ERRTAG_BMAPIFORMAT, XFS_RANDOM_BMAPIFORMAT))) { XFS_ERROR_REPORT("xfs_bmapi_read", XFS_ERRLEVEL_LOW, mp); return -EFSCORRUPTED; } if (XFS_FORCED_SHUTDOWN(mp)) return -EIO; XFS_STATS_INC(xs_blk_mapr); ifp = XFS_IFORK_PTR(ip, whichfork); if (!(ifp->if_flags & XFS_IFEXTENTS)) { error = xfs_iread_extents(NULL, ip, whichfork); if (error) return error; } xfs_bmap_search_extents(ip, bno, whichfork, &eof, &lastx, &got, &prev); end = bno + len; obno = bno; while (bno < end && n < *nmap) { /* Reading past eof, act as though there's a hole up to end. */ if (eof) got.br_startoff = end; if (got.br_startoff > bno) { /* Reading in a hole. */ mval->br_startoff = bno; mval->br_startblock = HOLESTARTBLOCK; mval->br_blockcount = XFS_FILBLKS_MIN(len, got.br_startoff - bno); mval->br_state = XFS_EXT_NORM; bno += mval->br_blockcount; len -= mval->br_blockcount; mval++; n++; continue; } /* set up the extent map to return. */ xfs_bmapi_trim_map(mval, &got, &bno, len, obno, end, n, flags); xfs_bmapi_update_map(&mval, &bno, &len, obno, end, &n, flags); /* If we're done, stop now. */ if (bno >= end || n >= *nmap) break; /* Else go on to the next record. */ if (++lastx < ifp->if_bytes / sizeof(xfs_bmbt_rec_t)) xfs_bmbt_get_all(xfs_iext_get_ext(ifp, lastx), &got); else eof = 1; } *nmap = n; return 0; } STATIC int xfs_bmapi_reserve_delalloc( struct xfs_inode *ip, xfs_fileoff_t aoff, xfs_filblks_t len, struct xfs_bmbt_irec *got, struct xfs_bmbt_irec *prev, xfs_extnum_t *lastx, int eof) { struct xfs_mount *mp = ip->i_mount; struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK); xfs_extlen_t alen; xfs_extlen_t indlen; char rt = XFS_IS_REALTIME_INODE(ip); xfs_extlen_t extsz; int error; alen = XFS_FILBLKS_MIN(len, MAXEXTLEN); if (!eof) alen = XFS_FILBLKS_MIN(alen, got->br_startoff - aoff); /* Figure out the extent size, adjust alen */ extsz = xfs_get_extsz_hint(ip); if (extsz) { error = xfs_bmap_extsize_align(mp, got, prev, extsz, rt, eof, 1, 0, &aoff, &alen); ASSERT(!error); } if (rt) extsz = alen / mp->m_sb.sb_rextsize; /* * Make a transaction-less quota reservation for delayed allocation * blocks. This number gets adjusted later. We return if we haven't * allocated blocks already inside this loop. */ error = xfs_trans_reserve_quota_nblks(NULL, ip, (long)alen, 0, rt ? XFS_QMOPT_RES_RTBLKS : XFS_QMOPT_RES_REGBLKS); if (error) return error; /* * Split changing sb for alen and indlen since they could be coming * from different places. */ indlen = (xfs_extlen_t)xfs_bmap_worst_indlen(ip, alen); ASSERT(indlen > 0); if (rt) { error = xfs_mod_frextents(mp, -((int64_t)extsz)); } else { error = xfs_mod_fdblocks(mp, -((int64_t)alen), false); } if (error) goto out_unreserve_quota; error = xfs_mod_fdblocks(mp, -((int64_t)indlen), false); if (error) goto out_unreserve_blocks; ip->i_delayed_blks += alen; got->br_startoff = aoff; got->br_startblock = nullstartblock(indlen); got->br_blockcount = alen; got->br_state = XFS_EXT_NORM; xfs_bmap_add_extent_hole_delay(ip, lastx, got); /* * Update our extent pointer, given that xfs_bmap_add_extent_hole_delay * might have merged it into one of the neighbouring ones. */ xfs_bmbt_get_all(xfs_iext_get_ext(ifp, *lastx), got); ASSERT(got->br_startoff <= aoff); ASSERT(got->br_startoff + got->br_blockcount >= aoff + alen); ASSERT(isnullstartblock(got->br_startblock)); ASSERT(got->br_state == XFS_EXT_NORM); return 0; out_unreserve_blocks: if (rt) xfs_mod_frextents(mp, extsz); else xfs_mod_fdblocks(mp, alen, false); out_unreserve_quota: if (XFS_IS_QUOTA_ON(mp)) xfs_trans_unreserve_quota_nblks(NULL, ip, (long)alen, 0, rt ? XFS_QMOPT_RES_RTBLKS : XFS_QMOPT_RES_REGBLKS); return error; } /* * Map file blocks to filesystem blocks, adding delayed allocations as needed. */ int xfs_bmapi_delay( struct xfs_inode *ip, /* incore inode */ xfs_fileoff_t bno, /* starting file offs. mapped */ xfs_filblks_t len, /* length to map in file */ struct xfs_bmbt_irec *mval, /* output: map values */ int *nmap, /* i/o: mval size/count */ int flags) /* XFS_BMAPI_... */ { struct xfs_mount *mp = ip->i_mount; struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK); struct xfs_bmbt_irec got; /* current file extent record */ struct xfs_bmbt_irec prev; /* previous file extent record */ xfs_fileoff_t obno; /* old block number (offset) */ xfs_fileoff_t end; /* end of mapped file region */ xfs_extnum_t lastx; /* last useful extent number */ int eof; /* we've hit the end of extents */ int n = 0; /* current extent index */ int error = 0; ASSERT(*nmap >= 1); ASSERT(*nmap <= XFS_BMAP_MAX_NMAP); ASSERT(!(flags & ~XFS_BMAPI_ENTIRE)); ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); if (unlikely(XFS_TEST_ERROR( (XFS_IFORK_FORMAT(ip, XFS_DATA_FORK) != XFS_DINODE_FMT_EXTENTS && XFS_IFORK_FORMAT(ip, XFS_DATA_FORK) != XFS_DINODE_FMT_BTREE), mp, XFS_ERRTAG_BMAPIFORMAT, XFS_RANDOM_BMAPIFORMAT))) { XFS_ERROR_REPORT("xfs_bmapi_delay", XFS_ERRLEVEL_LOW, mp); return -EFSCORRUPTED; } if (XFS_FORCED_SHUTDOWN(mp)) return -EIO; XFS_STATS_INC(xs_blk_mapw); if (!(ifp->if_flags & XFS_IFEXTENTS)) { error = xfs_iread_extents(NULL, ip, XFS_DATA_FORK); if (error) return error; } xfs_bmap_search_extents(ip, bno, XFS_DATA_FORK, &eof, &lastx, &got, &prev); end = bno + len; obno = bno; while (bno < end && n < *nmap) { if (eof || got.br_startoff > bno) { error = xfs_bmapi_reserve_delalloc(ip, bno, len, &got, &prev, &lastx, eof); if (error) { if (n == 0) { *nmap = 0; return error; } break; } } /* set up the extent map to return. */ xfs_bmapi_trim_map(mval, &got, &bno, len, obno, end, n, flags); xfs_bmapi_update_map(&mval, &bno, &len, obno, end, &n, flags); /* If we're done, stop now. */ if (bno >= end || n >= *nmap) break; /* Else go on to the next record. */ prev = got; if (++lastx < ifp->if_bytes / sizeof(xfs_bmbt_rec_t)) xfs_bmbt_get_all(xfs_iext_get_ext(ifp, lastx), &got); else eof = 1; } *nmap = n; return 0; } static int xfs_bmapi_allocate( struct xfs_bmalloca *bma) { struct xfs_mount *mp = bma->ip->i_mount; int whichfork = (bma->flags & XFS_BMAPI_ATTRFORK) ? XFS_ATTR_FORK : XFS_DATA_FORK; struct xfs_ifork *ifp = XFS_IFORK_PTR(bma->ip, whichfork); int tmp_logflags = 0; int error; ASSERT(bma->length > 0); /* * For the wasdelay case, we could also just allocate the stuff asked * for in this bmap call but that wouldn't be as good. */ if (bma->wasdel) { bma->length = (xfs_extlen_t)bma->got.br_blockcount; bma->offset = bma->got.br_startoff; if (bma->idx != NULLEXTNUM && bma->idx) { xfs_bmbt_get_all(xfs_iext_get_ext(ifp, bma->idx - 1), &bma->prev); } } else { bma->length = XFS_FILBLKS_MIN(bma->length, MAXEXTLEN); if (!bma->eof) bma->length = XFS_FILBLKS_MIN(bma->length, bma->got.br_startoff - bma->offset); } /* * Indicate if this is the first user data in the file, or just any * user data. */ if (!(bma->flags & XFS_BMAPI_METADATA)) { bma->userdata = (bma->offset == 0) ? XFS_ALLOC_INITIAL_USER_DATA : XFS_ALLOC_USERDATA; } bma->minlen = (bma->flags & XFS_BMAPI_CONTIG) ? bma->length : 1; /* * Only want to do the alignment at the eof if it is userdata and * allocation length is larger than a stripe unit. */ if (mp->m_dalign && bma->length >= mp->m_dalign && !(bma->flags & XFS_BMAPI_METADATA) && whichfork == XFS_DATA_FORK) { error = xfs_bmap_isaeof(bma, whichfork); if (error) return error; } error = xfs_bmap_alloc(bma); if (error) return error; if (bma->flist->xbf_low) bma->minleft = 0; if (bma->cur) bma->cur->bc_private.b.firstblock = *bma->firstblock; if (bma->blkno == NULLFSBLOCK) return 0; if ((ifp->if_flags & XFS_IFBROOT) && !bma->cur) { bma->cur = xfs_bmbt_init_cursor(mp, bma->tp, bma->ip, whichfork); bma->cur->bc_private.b.firstblock = *bma->firstblock; bma->cur->bc_private.b.flist = bma->flist; } /* * Bump the number of extents we've allocated * in this call. */ bma->nallocs++; if (bma->cur) bma->cur->bc_private.b.flags = bma->wasdel ? XFS_BTCUR_BPRV_WASDEL : 0; bma->got.br_startoff = bma->offset; bma->got.br_startblock = bma->blkno; bma->got.br_blockcount = bma->length; bma->got.br_state = XFS_EXT_NORM; /* * A wasdelay extent has been initialized, so shouldn't be flagged * as unwritten. */ if (!bma->wasdel && (bma->flags & XFS_BMAPI_PREALLOC) && xfs_sb_version_hasextflgbit(&mp->m_sb)) bma->got.br_state = XFS_EXT_UNWRITTEN; if (bma->wasdel) error = xfs_bmap_add_extent_delay_real(bma); else error = xfs_bmap_add_extent_hole_real(bma, whichfork); bma->logflags |= tmp_logflags; if (error) return error; /* * Update our extent pointer, given that xfs_bmap_add_extent_delay_real * or xfs_bmap_add_extent_hole_real might have merged it into one of * the neighbouring ones. */ xfs_bmbt_get_all(xfs_iext_get_ext(ifp, bma->idx), &bma->got); ASSERT(bma->got.br_startoff <= bma->offset); ASSERT(bma->got.br_startoff + bma->got.br_blockcount >= bma->offset + bma->length); ASSERT(bma->got.br_state == XFS_EXT_NORM || bma->got.br_state == XFS_EXT_UNWRITTEN); return 0; } STATIC int xfs_bmapi_convert_unwritten( struct xfs_bmalloca *bma, struct xfs_bmbt_irec *mval, xfs_filblks_t len, int flags) { int whichfork = (flags & XFS_BMAPI_ATTRFORK) ? XFS_ATTR_FORK : XFS_DATA_FORK; struct xfs_ifork *ifp = XFS_IFORK_PTR(bma->ip, whichfork); int tmp_logflags = 0; int error; /* check if we need to do unwritten->real conversion */ if (mval->br_state == XFS_EXT_UNWRITTEN && (flags & XFS_BMAPI_PREALLOC)) return 0; /* check if we need to do real->unwritten conversion */ if (mval->br_state == XFS_EXT_NORM && (flags & (XFS_BMAPI_PREALLOC | XFS_BMAPI_CONVERT)) != (XFS_BMAPI_PREALLOC | XFS_BMAPI_CONVERT)) return 0; /* * Modify (by adding) the state flag, if writing. */ ASSERT(mval->br_blockcount <= len); if ((ifp->if_flags & XFS_IFBROOT) && !bma->cur) { bma->cur = xfs_bmbt_init_cursor(bma->ip->i_mount, bma->tp, bma->ip, whichfork); bma->cur->bc_private.b.firstblock = *bma->firstblock; bma->cur->bc_private.b.flist = bma->flist; } mval->br_state = (mval->br_state == XFS_EXT_UNWRITTEN) ? XFS_EXT_NORM : XFS_EXT_UNWRITTEN; error = xfs_bmap_add_extent_unwritten_real(bma->tp, bma->ip, &bma->idx, &bma->cur, mval, bma->firstblock, bma->flist, &tmp_logflags); /* * Log the inode core unconditionally in the unwritten extent conversion * path because the conversion might not have done so (e.g., if the * extent count hasn't changed). We need to make sure the inode is dirty * in the transaction for the sake of fsync(), even if nothing has * changed, because fsync() will not force the log for this transaction * unless it sees the inode pinned. */ bma->logflags |= tmp_logflags | XFS_ILOG_CORE; if (error) return error; /* * Update our extent pointer, given that * xfs_bmap_add_extent_unwritten_real might have merged it into one * of the neighbouring ones. */ xfs_bmbt_get_all(xfs_iext_get_ext(ifp, bma->idx), &bma->got); /* * We may have combined previously unwritten space with written space, * so generate another request. */ if (mval->br_blockcount < len) return -EAGAIN; return 0; } /* * Map file blocks to filesystem blocks, and allocate blocks or convert the * extent state if necessary. Details behaviour is controlled by the flags * parameter. Only allocates blocks from a single allocation group, to avoid * locking problems. * * The returned value in "firstblock" from the first call in a transaction * must be remembered and presented to subsequent calls in "firstblock". * An upper bound for the number of blocks to be allocated is supplied to * the first call in "total"; if no allocation group has that many free * blocks then the call will fail (return NULLFSBLOCK in "firstblock"). */ int xfs_bmapi_write( struct xfs_trans *tp, /* transaction pointer */ struct xfs_inode *ip, /* incore inode */ xfs_fileoff_t bno, /* starting file offs. mapped */ xfs_filblks_t len, /* length to map in file */ int flags, /* XFS_BMAPI_... */ xfs_fsblock_t *firstblock, /* first allocated block controls a.g. for allocs */ xfs_extlen_t total, /* total blocks needed */ struct xfs_bmbt_irec *mval, /* output: map values */ int *nmap, /* i/o: mval size/count */ struct xfs_bmap_free *flist) /* i/o: list extents to free */ { struct xfs_mount *mp = ip->i_mount; struct xfs_ifork *ifp; struct xfs_bmalloca bma = { NULL }; /* args for xfs_bmap_alloc */ xfs_fileoff_t end; /* end of mapped file region */ int eof; /* after the end of extents */ int error; /* error return */ int n; /* current extent index */ xfs_fileoff_t obno; /* old block number (offset) */ int whichfork; /* data or attr fork */ char inhole; /* current location is hole in file */ char wasdelay; /* old extent was delayed */ #ifdef DEBUG xfs_fileoff_t orig_bno; /* original block number value */ int orig_flags; /* original flags arg value */ xfs_filblks_t orig_len; /* original value of len arg */ struct xfs_bmbt_irec *orig_mval; /* original value of mval */ int orig_nmap; /* original value of *nmap */ orig_bno = bno; orig_len = len; orig_flags = flags; orig_mval = mval; orig_nmap = *nmap; #endif whichfork = (flags & XFS_BMAPI_ATTRFORK) ? XFS_ATTR_FORK : XFS_DATA_FORK; ASSERT(*nmap >= 1); ASSERT(*nmap <= XFS_BMAP_MAX_NMAP); ASSERT(!(flags & XFS_BMAPI_IGSTATE)); ASSERT(tp != NULL); ASSERT(len > 0); ASSERT(XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_LOCAL); ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); if (unlikely(XFS_TEST_ERROR( (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS && XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE), mp, XFS_ERRTAG_BMAPIFORMAT, XFS_RANDOM_BMAPIFORMAT))) { XFS_ERROR_REPORT("xfs_bmapi_write", XFS_ERRLEVEL_LOW, mp); return -EFSCORRUPTED; } if (XFS_FORCED_SHUTDOWN(mp)) return -EIO; ifp = XFS_IFORK_PTR(ip, whichfork); XFS_STATS_INC(xs_blk_mapw); if (*firstblock == NULLFSBLOCK) { if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE) bma.minleft = be16_to_cpu(ifp->if_broot->bb_level) + 1; else bma.minleft = 1; } else { bma.minleft = 0; } if (!(ifp->if_flags & XFS_IFEXTENTS)) { error = xfs_iread_extents(tp, ip, whichfork); if (error) goto error0; } xfs_bmap_search_extents(ip, bno, whichfork, &eof, &bma.idx, &bma.got, &bma.prev); n = 0; end = bno + len; obno = bno; bma.tp = tp; bma.ip = ip; bma.total = total; bma.userdata = 0; bma.flist = flist; bma.firstblock = firstblock; while (bno < end && n < *nmap) { inhole = eof || bma.got.br_startoff > bno; wasdelay = !inhole && isnullstartblock(bma.got.br_startblock); /* * First, deal with the hole before the allocated space * that we found, if any. */ if (inhole || wasdelay) { bma.eof = eof; bma.conv = !!(flags & XFS_BMAPI_CONVERT); bma.wasdel = wasdelay; bma.offset = bno; bma.flags = flags; /* * There's a 32/64 bit type mismatch between the * allocation length request (which can be 64 bits in * length) and the bma length request, which is * xfs_extlen_t and therefore 32 bits. Hence we have to * check for 32-bit overflows and handle them here. */ if (len > (xfs_filblks_t)MAXEXTLEN) bma.length = MAXEXTLEN; else bma.length = len; ASSERT(len > 0); ASSERT(bma.length > 0); error = xfs_bmapi_allocate(&bma); if (error) goto error0; if (bma.blkno == NULLFSBLOCK) break; } /* Deal with the allocated space we found. */ xfs_bmapi_trim_map(mval, &bma.got, &bno, len, obno, end, n, flags); /* Execute unwritten extent conversion if necessary */ error = xfs_bmapi_convert_unwritten(&bma, mval, len, flags); if (error == -EAGAIN) continue; if (error) goto error0; /* update the extent map to return */ xfs_bmapi_update_map(&mval, &bno, &len, obno, end, &n, flags); /* * If we're done, stop now. Stop when we've allocated * XFS_BMAP_MAX_NMAP extents no matter what. Otherwise * the transaction may get too big. */ if (bno >= end || n >= *nmap || bma.nallocs >= *nmap) break; /* Else go on to the next record. */ bma.prev = bma.got; if (++bma.idx < ifp->if_bytes / sizeof(xfs_bmbt_rec_t)) { xfs_bmbt_get_all(xfs_iext_get_ext(ifp, bma.idx), &bma.got); } else eof = 1; } *nmap = n; /* * Transform from btree to extents, give it cur. */ if (xfs_bmap_wants_extents(ip, whichfork)) { int tmp_logflags = 0; ASSERT(bma.cur); error = xfs_bmap_btree_to_extents(tp, ip, bma.cur, &tmp_logflags, whichfork); bma.logflags |= tmp_logflags; if (error) goto error0; } ASSERT(XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE || XFS_IFORK_NEXTENTS(ip, whichfork) > XFS_IFORK_MAXEXT(ip, whichfork)); error = 0; error0: /* * Log everything. Do this after conversion, there's no point in * logging the extent records if we've converted to btree format. */ if ((bma.logflags & xfs_ilog_fext(whichfork)) && XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS) bma.logflags &= ~xfs_ilog_fext(whichfork); else if ((bma.logflags & xfs_ilog_fbroot(whichfork)) && XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE) bma.logflags &= ~xfs_ilog_fbroot(whichfork); /* * Log whatever the flags say, even if error. Otherwise we might miss * detecting a case where the data is changed, there's an error, * and it's not logged so we don't shutdown when we should. */ if (bma.logflags) xfs_trans_log_inode(tp, ip, bma.logflags); if (bma.cur) { if (!error) { ASSERT(*firstblock == NULLFSBLOCK || XFS_FSB_TO_AGNO(mp, *firstblock) == XFS_FSB_TO_AGNO(mp, bma.cur->bc_private.b.firstblock) || (flist->xbf_low && XFS_FSB_TO_AGNO(mp, *firstblock) < XFS_FSB_TO_AGNO(mp, bma.cur->bc_private.b.firstblock))); *firstblock = bma.cur->bc_private.b.firstblock; } xfs_btree_del_cursor(bma.cur, error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR); } if (!error) xfs_bmap_validate_ret(orig_bno, orig_len, orig_flags, orig_mval, orig_nmap, *nmap); return error; } /* * Called by xfs_bmapi to update file extent records and the btree * after removing space (or undoing a delayed allocation). */ STATIC int /* error */ xfs_bmap_del_extent( xfs_inode_t *ip, /* incore inode pointer */ xfs_trans_t *tp, /* current transaction pointer */ xfs_extnum_t *idx, /* extent number to update/delete */ xfs_bmap_free_t *flist, /* list of extents to be freed */ xfs_btree_cur_t *cur, /* if null, not a btree */ xfs_bmbt_irec_t *del, /* data to remove from extents */ int *logflagsp, /* inode logging flags */ int whichfork) /* data or attr fork */ { xfs_filblks_t da_new; /* new delay-alloc indirect blocks */ xfs_filblks_t da_old; /* old delay-alloc indirect blocks */ xfs_fsblock_t del_endblock=0; /* first block past del */ xfs_fileoff_t del_endoff; /* first offset past del */ int delay; /* current block is delayed allocated */ int do_fx; /* free extent at end of routine */ xfs_bmbt_rec_host_t *ep; /* current extent entry pointer */ int error; /* error return value */ int flags; /* inode logging flags */ xfs_bmbt_irec_t got; /* current extent entry */ xfs_fileoff_t got_endoff; /* first offset past got */ int i; /* temp state */ xfs_ifork_t *ifp; /* inode fork pointer */ xfs_mount_t *mp; /* mount structure */ xfs_filblks_t nblks; /* quota/sb block count */ xfs_bmbt_irec_t new; /* new record to be inserted */ /* REFERENCED */ uint qfield; /* quota field to update */ xfs_filblks_t temp; /* for indirect length calculations */ xfs_filblks_t temp2; /* for indirect length calculations */ int state = 0; XFS_STATS_INC(xs_del_exlist); if (whichfork == XFS_ATTR_FORK) state |= BMAP_ATTRFORK; mp = ip->i_mount; ifp = XFS_IFORK_PTR(ip, whichfork); ASSERT((*idx >= 0) && (*idx < ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t))); ASSERT(del->br_blockcount > 0); ep = xfs_iext_get_ext(ifp, *idx); xfs_bmbt_get_all(ep, &got); ASSERT(got.br_startoff <= del->br_startoff); del_endoff = del->br_startoff + del->br_blockcount; got_endoff = got.br_startoff + got.br_blockcount; ASSERT(got_endoff >= del_endoff); delay = isnullstartblock(got.br_startblock); ASSERT(isnullstartblock(del->br_startblock) == delay); flags = 0; qfield = 0; error = 0; /* * If deleting a real allocation, must free up the disk space. */ if (!delay) { flags = XFS_ILOG_CORE; /* * Realtime allocation. Free it and record di_nblocks update. */ if (whichfork == XFS_DATA_FORK && XFS_IS_REALTIME_INODE(ip)) { xfs_fsblock_t bno; xfs_filblks_t len; ASSERT(do_mod(del->br_blockcount, mp->m_sb.sb_rextsize) == 0); ASSERT(do_mod(del->br_startblock, mp->m_sb.sb_rextsize) == 0); bno = del->br_startblock; len = del->br_blockcount; do_div(bno, mp->m_sb.sb_rextsize); do_div(len, mp->m_sb.sb_rextsize); error = xfs_rtfree_extent(tp, bno, (xfs_extlen_t)len); if (error) goto done; do_fx = 0; nblks = len * mp->m_sb.sb_rextsize; qfield = XFS_TRANS_DQ_RTBCOUNT; } /* * Ordinary allocation. */ else { do_fx = 1; nblks = del->br_blockcount; qfield = XFS_TRANS_DQ_BCOUNT; } /* * Set up del_endblock and cur for later. */ del_endblock = del->br_startblock + del->br_blockcount; if (cur) { if ((error = xfs_bmbt_lookup_eq(cur, got.br_startoff, got.br_startblock, got.br_blockcount, &i))) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); } da_old = da_new = 0; } else { da_old = startblockval(got.br_startblock); da_new = 0; nblks = 0; do_fx = 0; } /* * Set flag value to use in switch statement. * Left-contig is 2, right-contig is 1. */ switch (((got.br_startoff == del->br_startoff) << 1) | (got_endoff == del_endoff)) { case 3: /* * Matches the whole extent. Delete the entry. */ xfs_iext_remove(ip, *idx, 1, whichfork == XFS_ATTR_FORK ? BMAP_ATTRFORK : 0); --*idx; if (delay) break; XFS_IFORK_NEXT_SET(ip, whichfork, XFS_IFORK_NEXTENTS(ip, whichfork) - 1); flags |= XFS_ILOG_CORE; if (!cur) { flags |= xfs_ilog_fext(whichfork); break; } if ((error = xfs_btree_delete(cur, &i))) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); break; case 2: /* * Deleting the first part of the extent. */ trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_); xfs_bmbt_set_startoff(ep, del_endoff); temp = got.br_blockcount - del->br_blockcount; xfs_bmbt_set_blockcount(ep, temp); if (delay) { temp = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp), da_old); xfs_bmbt_set_startblock(ep, nullstartblock((int)temp)); trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_); da_new = temp; break; } xfs_bmbt_set_startblock(ep, del_endblock); trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_); if (!cur) { flags |= xfs_ilog_fext(whichfork); break; } if ((error = xfs_bmbt_update(cur, del_endoff, del_endblock, got.br_blockcount - del->br_blockcount, got.br_state))) goto done; break; case 1: /* * Deleting the last part of the extent. */ temp = got.br_blockcount - del->br_blockcount; trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_); xfs_bmbt_set_blockcount(ep, temp); if (delay) { temp = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp), da_old); xfs_bmbt_set_startblock(ep, nullstartblock((int)temp)); trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_); da_new = temp; break; } trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_); if (!cur) { flags |= xfs_ilog_fext(whichfork); break; } if ((error = xfs_bmbt_update(cur, got.br_startoff, got.br_startblock, got.br_blockcount - del->br_blockcount, got.br_state))) goto done; break; case 0: /* * Deleting the middle of the extent. */ temp = del->br_startoff - got.br_startoff; trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_); xfs_bmbt_set_blockcount(ep, temp); new.br_startoff = del_endoff; temp2 = got_endoff - del_endoff; new.br_blockcount = temp2; new.br_state = got.br_state; if (!delay) { new.br_startblock = del_endblock; flags |= XFS_ILOG_CORE; if (cur) { if ((error = xfs_bmbt_update(cur, got.br_startoff, got.br_startblock, temp, got.br_state))) goto done; if ((error = xfs_btree_increment(cur, 0, &i))) goto done; cur->bc_rec.b = new; error = xfs_btree_insert(cur, &i); if (error && error != -ENOSPC) goto done; /* * If get no-space back from btree insert, * it tried a split, and we have a zero * block reservation. * Fix up our state and return the error. */ if (error == -ENOSPC) { /* * Reset the cursor, don't trust * it after any insert operation. */ if ((error = xfs_bmbt_lookup_eq(cur, got.br_startoff, got.br_startblock, temp, &i))) goto done; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); /* * Update the btree record back * to the original value. */ if ((error = xfs_bmbt_update(cur, got.br_startoff, got.br_startblock, got.br_blockcount, got.br_state))) goto done; /* * Reset the extent record back * to the original value. */ xfs_bmbt_set_blockcount(ep, got.br_blockcount); flags = 0; error = -ENOSPC; goto done; } XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); } else flags |= xfs_ilog_fext(whichfork); XFS_IFORK_NEXT_SET(ip, whichfork, XFS_IFORK_NEXTENTS(ip, whichfork) + 1); } else { ASSERT(whichfork == XFS_DATA_FORK); temp = xfs_bmap_worst_indlen(ip, temp); xfs_bmbt_set_startblock(ep, nullstartblock((int)temp)); temp2 = xfs_bmap_worst_indlen(ip, temp2); new.br_startblock = nullstartblock((int)temp2); da_new = temp + temp2; while (da_new > da_old) { if (temp) { temp--; da_new--; xfs_bmbt_set_startblock(ep, nullstartblock((int)temp)); } if (da_new == da_old) break; if (temp2) { temp2--; da_new--; new.br_startblock = nullstartblock((int)temp2); } } } trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_); xfs_iext_insert(ip, *idx + 1, 1, &new, state); ++*idx; break; } /* * If we need to, add to list of extents to delete. */ if (do_fx) xfs_bmap_add_free(del->br_startblock, del->br_blockcount, flist, mp); /* * Adjust inode # blocks in the file. */ if (nblks) ip->i_d.di_nblocks -= nblks; /* * Adjust quota data. */ if (qfield) xfs_trans_mod_dquot_byino(tp, ip, qfield, (long)-nblks); /* * Account for change in delayed indirect blocks. * Nothing to do for disk quota accounting here. */ ASSERT(da_old >= da_new); if (da_old > da_new) xfs_mod_fdblocks(mp, (int64_t)(da_old - da_new), false); done: *logflagsp = flags; return error; } /* * Unmap (remove) blocks from a file. * If nexts is nonzero then the number of extents to remove is limited to * that value. If not all extents in the block range can be removed then * *done is set. */ int /* error */ xfs_bunmapi( xfs_trans_t *tp, /* transaction pointer */ struct xfs_inode *ip, /* incore inode */ xfs_fileoff_t bno, /* starting offset to unmap */ xfs_filblks_t len, /* length to unmap in file */ int flags, /* misc flags */ xfs_extnum_t nexts, /* number of extents max */ xfs_fsblock_t *firstblock, /* first allocated block controls a.g. for allocs */ xfs_bmap_free_t *flist, /* i/o: list extents to free */ int *done) /* set if not done yet */ { xfs_btree_cur_t *cur; /* bmap btree cursor */ xfs_bmbt_irec_t del; /* extent being deleted */ int eof; /* is deleting at eof */ xfs_bmbt_rec_host_t *ep; /* extent record pointer */ int error; /* error return value */ xfs_extnum_t extno; /* extent number in list */ xfs_bmbt_irec_t got; /* current extent record */ xfs_ifork_t *ifp; /* inode fork pointer */ int isrt; /* freeing in rt area */ xfs_extnum_t lastx; /* last extent index used */ int logflags; /* transaction logging flags */ xfs_extlen_t mod; /* rt extent offset */ xfs_mount_t *mp; /* mount structure */ xfs_extnum_t nextents; /* number of file extents */ xfs_bmbt_irec_t prev; /* previous extent record */ xfs_fileoff_t start; /* first file offset deleted */ int tmp_logflags; /* partial logging flags */ int wasdel; /* was a delayed alloc extent */ int whichfork; /* data or attribute fork */ xfs_fsblock_t sum; trace_xfs_bunmap(ip, bno, len, flags, _RET_IP_); whichfork = (flags & XFS_BMAPI_ATTRFORK) ? XFS_ATTR_FORK : XFS_DATA_FORK; ifp = XFS_IFORK_PTR(ip, whichfork); if (unlikely( XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS && XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE)) { XFS_ERROR_REPORT("xfs_bunmapi", XFS_ERRLEVEL_LOW, ip->i_mount); return -EFSCORRUPTED; } mp = ip->i_mount; if (XFS_FORCED_SHUTDOWN(mp)) return -EIO; ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); ASSERT(len > 0); ASSERT(nexts >= 0); if (!(ifp->if_flags & XFS_IFEXTENTS) && (error = xfs_iread_extents(tp, ip, whichfork))) return error; nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); if (nextents == 0) { *done = 1; return 0; } XFS_STATS_INC(xs_blk_unmap); isrt = (whichfork == XFS_DATA_FORK) && XFS_IS_REALTIME_INODE(ip); start = bno; bno = start + len - 1; ep = xfs_bmap_search_extents(ip, bno, whichfork, &eof, &lastx, &got, &prev); /* * Check to see if the given block number is past the end of the * file, back up to the last block if so... */ if (eof) { ep = xfs_iext_get_ext(ifp, --lastx); xfs_bmbt_get_all(ep, &got); bno = got.br_startoff + got.br_blockcount - 1; } logflags = 0; if (ifp->if_flags & XFS_IFBROOT) { ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE); cur = xfs_bmbt_init_cursor(mp, tp, ip, whichfork); cur->bc_private.b.firstblock = *firstblock; cur->bc_private.b.flist = flist; cur->bc_private.b.flags = 0; } else cur = NULL; if (isrt) { /* * Synchronize by locking the bitmap inode. */ xfs_ilock(mp->m_rbmip, XFS_ILOCK_EXCL); xfs_trans_ijoin(tp, mp->m_rbmip, XFS_ILOCK_EXCL); } extno = 0; while (bno != (xfs_fileoff_t)-1 && bno >= start && lastx >= 0 && (nexts == 0 || extno < nexts)) { /* * Is the found extent after a hole in which bno lives? * Just back up to the previous extent, if so. */ if (got.br_startoff > bno) { if (--lastx < 0) break; ep = xfs_iext_get_ext(ifp, lastx); xfs_bmbt_get_all(ep, &got); } /* * Is the last block of this extent before the range * we're supposed to delete? If so, we're done. */ bno = XFS_FILEOFF_MIN(bno, got.br_startoff + got.br_blockcount - 1); if (bno < start) break; /* * Then deal with the (possibly delayed) allocated space * we found. */ ASSERT(ep != NULL); del = got; wasdel = isnullstartblock(del.br_startblock); if (got.br_startoff < start) { del.br_startoff = start; del.br_blockcount -= start - got.br_startoff; if (!wasdel) del.br_startblock += start - got.br_startoff; } if (del.br_startoff + del.br_blockcount > bno + 1) del.br_blockcount = bno + 1 - del.br_startoff; sum = del.br_startblock + del.br_blockcount; if (isrt && (mod = do_mod(sum, mp->m_sb.sb_rextsize))) { /* * Realtime extent not lined up at the end. * The extent could have been split into written * and unwritten pieces, or we could just be * unmapping part of it. But we can't really * get rid of part of a realtime extent. */ if (del.br_state == XFS_EXT_UNWRITTEN || !xfs_sb_version_hasextflgbit(&mp->m_sb)) { /* * This piece is unwritten, or we're not * using unwritten extents. Skip over it. */ ASSERT(bno >= mod); bno -= mod > del.br_blockcount ? del.br_blockcount : mod; if (bno < got.br_startoff) { if (--lastx >= 0) xfs_bmbt_get_all(xfs_iext_get_ext( ifp, lastx), &got); } continue; } /* * It's written, turn it unwritten. * This is better than zeroing it. */ ASSERT(del.br_state == XFS_EXT_NORM); ASSERT(xfs_trans_get_block_res(tp) > 0); /* * If this spans a realtime extent boundary, * chop it back to the start of the one we end at. */ if (del.br_blockcount > mod) { del.br_startoff += del.br_blockcount - mod; del.br_startblock += del.br_blockcount - mod; del.br_blockcount = mod; } del.br_state = XFS_EXT_UNWRITTEN; error = xfs_bmap_add_extent_unwritten_real(tp, ip, &lastx, &cur, &del, firstblock, flist, &logflags); if (error) goto error0; goto nodelete; } if (isrt && (mod = do_mod(del.br_startblock, mp->m_sb.sb_rextsize))) { /* * Realtime extent is lined up at the end but not * at the front. We'll get rid of full extents if * we can. */ mod = mp->m_sb.sb_rextsize - mod; if (del.br_blockcount > mod) { del.br_blockcount -= mod; del.br_startoff += mod; del.br_startblock += mod; } else if ((del.br_startoff == start && (del.br_state == XFS_EXT_UNWRITTEN || xfs_trans_get_block_res(tp) == 0)) || !xfs_sb_version_hasextflgbit(&mp->m_sb)) { /* * Can't make it unwritten. There isn't * a full extent here so just skip it. */ ASSERT(bno >= del.br_blockcount); bno -= del.br_blockcount; if (got.br_startoff > bno) { if (--lastx >= 0) { ep = xfs_iext_get_ext(ifp, lastx); xfs_bmbt_get_all(ep, &got); } } continue; } else if (del.br_state == XFS_EXT_UNWRITTEN) { /* * This one is already unwritten. * It must have a written left neighbor. * Unwrite the killed part of that one and * try again. */ ASSERT(lastx > 0); xfs_bmbt_get_all(xfs_iext_get_ext(ifp, lastx - 1), &prev); ASSERT(prev.br_state == XFS_EXT_NORM); ASSERT(!isnullstartblock(prev.br_startblock)); ASSERT(del.br_startblock == prev.br_startblock + prev.br_blockcount); if (prev.br_startoff < start) { mod = start - prev.br_startoff; prev.br_blockcount -= mod; prev.br_startblock += mod; prev.br_startoff = start; } prev.br_state = XFS_EXT_UNWRITTEN; lastx--; error = xfs_bmap_add_extent_unwritten_real(tp, ip, &lastx, &cur, &prev, firstblock, flist, &logflags); if (error) goto error0; goto nodelete; } else { ASSERT(del.br_state == XFS_EXT_NORM); del.br_state = XFS_EXT_UNWRITTEN; error = xfs_bmap_add_extent_unwritten_real(tp, ip, &lastx, &cur, &del, firstblock, flist, &logflags); if (error) goto error0; goto nodelete; } } if (wasdel) { ASSERT(startblockval(del.br_startblock) > 0); /* Update realtime/data freespace, unreserve quota */ if (isrt) { xfs_filblks_t rtexts; rtexts = XFS_FSB_TO_B(mp, del.br_blockcount); do_div(rtexts, mp->m_sb.sb_rextsize); xfs_mod_frextents(mp, (int64_t)rtexts); (void)xfs_trans_reserve_quota_nblks(NULL, ip, -((long)del.br_blockcount), 0, XFS_QMOPT_RES_RTBLKS); } else { xfs_mod_fdblocks(mp, (int64_t)del.br_blockcount, false); (void)xfs_trans_reserve_quota_nblks(NULL, ip, -((long)del.br_blockcount), 0, XFS_QMOPT_RES_REGBLKS); } ip->i_delayed_blks -= del.br_blockcount; if (cur) cur->bc_private.b.flags |= XFS_BTCUR_BPRV_WASDEL; } else if (cur) cur->bc_private.b.flags &= ~XFS_BTCUR_BPRV_WASDEL; /* * If it's the case where the directory code is running * with no block reservation, and the deleted block is in * the middle of its extent, and the resulting insert * of an extent would cause transformation to btree format, * then reject it. The calling code will then swap * blocks around instead. * We have to do this now, rather than waiting for the * conversion to btree format, since the transaction * will be dirty. */ if (!wasdel && xfs_trans_get_block_res(tp) == 0 && XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_EXTENTS && XFS_IFORK_NEXTENTS(ip, whichfork) >= /* Note the >= */ XFS_IFORK_MAXEXT(ip, whichfork) && del.br_startoff > got.br_startoff && del.br_startoff + del.br_blockcount < got.br_startoff + got.br_blockcount) { error = -ENOSPC; goto error0; } error = xfs_bmap_del_extent(ip, tp, &lastx, flist, cur, &del, &tmp_logflags, whichfork); logflags |= tmp_logflags; if (error) goto error0; bno = del.br_startoff - 1; nodelete: /* * If not done go on to the next (previous) record. */ if (bno != (xfs_fileoff_t)-1 && bno >= start) { if (lastx >= 0) { ep = xfs_iext_get_ext(ifp, lastx); if (xfs_bmbt_get_startoff(ep) > bno) { if (--lastx >= 0) ep = xfs_iext_get_ext(ifp, lastx); } xfs_bmbt_get_all(ep, &got); } extno++; } } *done = bno == (xfs_fileoff_t)-1 || bno < start || lastx < 0; /* * Convert to a btree if necessary. */ if (xfs_bmap_needs_btree(ip, whichfork)) { ASSERT(cur == NULL); error = xfs_bmap_extents_to_btree(tp, ip, firstblock, flist, &cur, 0, &tmp_logflags, whichfork); logflags |= tmp_logflags; if (error) goto error0; } /* * transform from btree to extents, give it cur */ else if (xfs_bmap_wants_extents(ip, whichfork)) { ASSERT(cur != NULL); error = xfs_bmap_btree_to_extents(tp, ip, cur, &tmp_logflags, whichfork); logflags |= tmp_logflags; if (error) goto error0; } /* * transform from extents to local? */ error = 0; error0: /* * Log everything. Do this after conversion, there's no point in * logging the extent records if we've converted to btree format. */ if ((logflags & xfs_ilog_fext(whichfork)) && XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS) logflags &= ~xfs_ilog_fext(whichfork); else if ((logflags & xfs_ilog_fbroot(whichfork)) && XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE) logflags &= ~xfs_ilog_fbroot(whichfork); /* * Log inode even in the error case, if the transaction * is dirty we'll need to shut down the filesystem. */ if (logflags) xfs_trans_log_inode(tp, ip, logflags); if (cur) { if (!error) { *firstblock = cur->bc_private.b.firstblock; cur->bc_private.b.allocated = 0; } xfs_btree_del_cursor(cur, error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR); } return error; } /* * Determine whether an extent shift can be accomplished by a merge with the * extent that precedes the target hole of the shift. */ STATIC bool xfs_bmse_can_merge( struct xfs_bmbt_irec *left, /* preceding extent */ struct xfs_bmbt_irec *got, /* current extent to shift */ xfs_fileoff_t shift) /* shift fsb */ { xfs_fileoff_t startoff; startoff = got->br_startoff - shift; /* * The extent, once shifted, must be adjacent in-file and on-disk with * the preceding extent. */ if ((left->br_startoff + left->br_blockcount != startoff) || (left->br_startblock + left->br_blockcount != got->br_startblock) || (left->br_state != got->br_state) || (left->br_blockcount + got->br_blockcount > MAXEXTLEN)) return false; return true; } /* * A bmap extent shift adjusts the file offset of an extent to fill a preceding * hole in the file. If an extent shift would result in the extent being fully * adjacent to the extent that currently precedes the hole, we can merge with * the preceding extent rather than do the shift. * * This function assumes the caller has verified a shift-by-merge is possible * with the provided extents via xfs_bmse_can_merge(). */ STATIC int xfs_bmse_merge( struct xfs_inode *ip, int whichfork, xfs_fileoff_t shift, /* shift fsb */ int current_ext, /* idx of gotp */ struct xfs_bmbt_rec_host *gotp, /* extent to shift */ struct xfs_bmbt_rec_host *leftp, /* preceding extent */ struct xfs_btree_cur *cur, int *logflags) /* output */ { struct xfs_bmbt_irec got; struct xfs_bmbt_irec left; xfs_filblks_t blockcount; int error, i; struct xfs_mount *mp = ip->i_mount; xfs_bmbt_get_all(gotp, &got); xfs_bmbt_get_all(leftp, &left); blockcount = left.br_blockcount + got.br_blockcount; ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL)); ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); ASSERT(xfs_bmse_can_merge(&left, &got, shift)); /* * Merge the in-core extents. Note that the host record pointers and * current_ext index are invalid once the extent has been removed via * xfs_iext_remove(). */ xfs_bmbt_set_blockcount(leftp, blockcount); xfs_iext_remove(ip, current_ext, 1, 0); /* * Update the on-disk extent count, the btree if necessary and log the * inode. */ XFS_IFORK_NEXT_SET(ip, whichfork, XFS_IFORK_NEXTENTS(ip, whichfork) - 1); *logflags |= XFS_ILOG_CORE; if (!cur) { *logflags |= XFS_ILOG_DEXT; return 0; } /* lookup and remove the extent to merge */ error = xfs_bmbt_lookup_eq(cur, got.br_startoff, got.br_startblock, got.br_blockcount, &i); if (error) return error; XFS_WANT_CORRUPTED_RETURN(mp, i == 1); error = xfs_btree_delete(cur, &i); if (error) return error; XFS_WANT_CORRUPTED_RETURN(mp, i == 1); /* lookup and update size of the previous extent */ error = xfs_bmbt_lookup_eq(cur, left.br_startoff, left.br_startblock, left.br_blockcount, &i); if (error) return error; XFS_WANT_CORRUPTED_RETURN(mp, i == 1); left.br_blockcount = blockcount; return xfs_bmbt_update(cur, left.br_startoff, left.br_startblock, left.br_blockcount, left.br_state); } /* * Shift a single extent. */ STATIC int xfs_bmse_shift_one( struct xfs_inode *ip, int whichfork, xfs_fileoff_t offset_shift_fsb, int *current_ext, struct xfs_bmbt_rec_host *gotp, struct xfs_btree_cur *cur, int *logflags, enum shift_direction direction) { struct xfs_ifork *ifp; struct xfs_mount *mp; xfs_fileoff_t startoff; struct xfs_bmbt_rec_host *adj_irecp; struct xfs_bmbt_irec got; struct xfs_bmbt_irec adj_irec; int error; int i; int total_extents; mp = ip->i_mount; ifp = XFS_IFORK_PTR(ip, whichfork); total_extents = ifp->if_bytes / sizeof(xfs_bmbt_rec_t); xfs_bmbt_get_all(gotp, &got); /* delalloc extents should be prevented by caller */ XFS_WANT_CORRUPTED_RETURN(mp, !isnullstartblock(got.br_startblock)); if (direction == SHIFT_LEFT) { startoff = got.br_startoff - offset_shift_fsb; /* * Check for merge if we've got an extent to the left, * otherwise make sure there's enough room at the start * of the file for the shift. */ if (!*current_ext) { if (got.br_startoff < offset_shift_fsb) return -EINVAL; goto update_current_ext; } /* * grab the left extent and check for a large * enough hole. */ adj_irecp = xfs_iext_get_ext(ifp, *current_ext - 1); xfs_bmbt_get_all(adj_irecp, &adj_irec); if (startoff < adj_irec.br_startoff + adj_irec.br_blockcount) return -EINVAL; /* check whether to merge the extent or shift it down */ if (xfs_bmse_can_merge(&adj_irec, &got, offset_shift_fsb)) { return xfs_bmse_merge(ip, whichfork, offset_shift_fsb, *current_ext, gotp, adj_irecp, cur, logflags); } } else { startoff = got.br_startoff + offset_shift_fsb; /* nothing to move if this is the last extent */ if (*current_ext >= (total_extents - 1)) goto update_current_ext; /* * If this is not the last extent in the file, make sure there * is enough room between current extent and next extent for * accommodating the shift. */ adj_irecp = xfs_iext_get_ext(ifp, *current_ext + 1); xfs_bmbt_get_all(adj_irecp, &adj_irec); if (startoff + got.br_blockcount > adj_irec.br_startoff) return -EINVAL; /* * Unlike a left shift (which involves a hole punch), * a right shift does not modify extent neighbors * in any way. We should never find mergeable extents * in this scenario. Check anyways and warn if we * encounter two extents that could be one. */ if (xfs_bmse_can_merge(&got, &adj_irec, offset_shift_fsb)) WARN_ON_ONCE(1); } /* * Increment the extent index for the next iteration, update the start * offset of the in-core extent and update the btree if applicable. */ update_current_ext: if (direction == SHIFT_LEFT) (*current_ext)++; else (*current_ext)--; xfs_bmbt_set_startoff(gotp, startoff); *logflags |= XFS_ILOG_CORE; if (!cur) { *logflags |= XFS_ILOG_DEXT; return 0; } error = xfs_bmbt_lookup_eq(cur, got.br_startoff, got.br_startblock, got.br_blockcount, &i); if (error) return error; XFS_WANT_CORRUPTED_RETURN(mp, i == 1); got.br_startoff = startoff; return xfs_bmbt_update(cur, got.br_startoff, got.br_startblock, got.br_blockcount, got.br_state); } /* * Shift extent records to the left/right to cover/create a hole. * * The maximum number of extents to be shifted in a single operation is * @num_exts. @stop_fsb specifies the file offset at which to stop shift and the * file offset where we've left off is returned in @next_fsb. @offset_shift_fsb * is the length by which each extent is shifted. If there is no hole to shift * the extents into, this will be considered invalid operation and we abort * immediately. */ int xfs_bmap_shift_extents( struct xfs_trans *tp, struct xfs_inode *ip, xfs_fileoff_t *next_fsb, xfs_fileoff_t offset_shift_fsb, int *done, xfs_fileoff_t stop_fsb, xfs_fsblock_t *firstblock, struct xfs_bmap_free *flist, enum shift_direction direction, int num_exts) { struct xfs_btree_cur *cur = NULL; struct xfs_bmbt_rec_host *gotp; struct xfs_bmbt_irec got; struct xfs_mount *mp = ip->i_mount; struct xfs_ifork *ifp; xfs_extnum_t nexts = 0; xfs_extnum_t current_ext; xfs_extnum_t total_extents; xfs_extnum_t stop_extent; int error = 0; int whichfork = XFS_DATA_FORK; int logflags = 0; if (unlikely(XFS_TEST_ERROR( (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS && XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE), mp, XFS_ERRTAG_BMAPIFORMAT, XFS_RANDOM_BMAPIFORMAT))) { XFS_ERROR_REPORT("xfs_bmap_shift_extents", XFS_ERRLEVEL_LOW, mp); return -EFSCORRUPTED; } if (XFS_FORCED_SHUTDOWN(mp)) return -EIO; ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL)); ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); ASSERT(direction == SHIFT_LEFT || direction == SHIFT_RIGHT); ASSERT(*next_fsb != NULLFSBLOCK || direction == SHIFT_RIGHT); ifp = XFS_IFORK_PTR(ip, whichfork); if (!(ifp->if_flags & XFS_IFEXTENTS)) { /* Read in all the extents */ error = xfs_iread_extents(tp, ip, whichfork); if (error) return error; } if (ifp->if_flags & XFS_IFBROOT) { cur = xfs_bmbt_init_cursor(mp, tp, ip, whichfork); cur->bc_private.b.firstblock = *firstblock; cur->bc_private.b.flist = flist; cur->bc_private.b.flags = 0; } /* * There may be delalloc extents in the data fork before the range we * are collapsing out, so we cannot use the count of real extents here. * Instead we have to calculate it from the incore fork. */ total_extents = ifp->if_bytes / sizeof(xfs_bmbt_rec_t); if (total_extents == 0) { *done = 1; goto del_cursor; } /* * In case of first right shift, we need to initialize next_fsb */ if (*next_fsb == NULLFSBLOCK) { gotp = xfs_iext_get_ext(ifp, total_extents - 1); xfs_bmbt_get_all(gotp, &got); *next_fsb = got.br_startoff; if (stop_fsb > *next_fsb) { *done = 1; goto del_cursor; } } /* Lookup the extent index at which we have to stop */ if (direction == SHIFT_RIGHT) { gotp = xfs_iext_bno_to_ext(ifp, stop_fsb, &stop_extent); /* Make stop_extent exclusive of shift range */ stop_extent--; } else stop_extent = total_extents; /* * Look up the extent index for the fsb where we start shifting. We can * henceforth iterate with current_ext as extent list changes are locked * out via ilock. * * gotp can be null in 2 cases: 1) if there are no extents or 2) * *next_fsb lies in a hole beyond which there are no extents. Either * way, we are done. */ gotp = xfs_iext_bno_to_ext(ifp, *next_fsb, ¤t_ext); if (!gotp) { *done = 1; goto del_cursor; } /* some sanity checking before we finally start shifting extents */ if ((direction == SHIFT_LEFT && current_ext >= stop_extent) || (direction == SHIFT_RIGHT && current_ext <= stop_extent)) { error = -EIO; goto del_cursor; } while (nexts++ < num_exts) { error = xfs_bmse_shift_one(ip, whichfork, offset_shift_fsb, ¤t_ext, gotp, cur, &logflags, direction); if (error) goto del_cursor; /* * If there was an extent merge during the shift, the extent * count can change. Update the total and grade the next record. */ if (direction == SHIFT_LEFT) { total_extents = ifp->if_bytes / sizeof(xfs_bmbt_rec_t); stop_extent = total_extents; } if (current_ext == stop_extent) { *done = 1; *next_fsb = NULLFSBLOCK; break; } gotp = xfs_iext_get_ext(ifp, current_ext); } if (!*done) { xfs_bmbt_get_all(gotp, &got); *next_fsb = got.br_startoff; } del_cursor: if (cur) xfs_btree_del_cursor(cur, error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR); if (logflags) xfs_trans_log_inode(tp, ip, logflags); return error; } /* * Splits an extent into two extents at split_fsb block such that it is * the first block of the current_ext. @current_ext is a target extent * to be split. @split_fsb is a block where the extents is split. * If split_fsb lies in a hole or the first block of extents, just return 0. */ STATIC int xfs_bmap_split_extent_at( struct xfs_trans *tp, struct xfs_inode *ip, xfs_fileoff_t split_fsb, xfs_fsblock_t *firstfsb, struct xfs_bmap_free *free_list) { int whichfork = XFS_DATA_FORK; struct xfs_btree_cur *cur = NULL; struct xfs_bmbt_rec_host *gotp; struct xfs_bmbt_irec got; struct xfs_bmbt_irec new; /* split extent */ struct xfs_mount *mp = ip->i_mount; struct xfs_ifork *ifp; xfs_fsblock_t gotblkcnt; /* new block count for got */ xfs_extnum_t current_ext; int error = 0; int logflags = 0; int i = 0; if (unlikely(XFS_TEST_ERROR( (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS && XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE), mp, XFS_ERRTAG_BMAPIFORMAT, XFS_RANDOM_BMAPIFORMAT))) { XFS_ERROR_REPORT("xfs_bmap_split_extent_at", XFS_ERRLEVEL_LOW, mp); return -EFSCORRUPTED; } if (XFS_FORCED_SHUTDOWN(mp)) return -EIO; ifp = XFS_IFORK_PTR(ip, whichfork); if (!(ifp->if_flags & XFS_IFEXTENTS)) { /* Read in all the extents */ error = xfs_iread_extents(tp, ip, whichfork); if (error) return error; } /* * gotp can be null in 2 cases: 1) if there are no extents * or 2) split_fsb lies in a hole beyond which there are * no extents. Either way, we are done. */ gotp = xfs_iext_bno_to_ext(ifp, split_fsb, ¤t_ext); if (!gotp) return 0; xfs_bmbt_get_all(gotp, &got); /* * Check split_fsb lies in a hole or the start boundary offset * of the extent. */ if (got.br_startoff >= split_fsb) return 0; gotblkcnt = split_fsb - got.br_startoff; new.br_startoff = split_fsb; new.br_startblock = got.br_startblock + gotblkcnt; new.br_blockcount = got.br_blockcount - gotblkcnt; new.br_state = got.br_state; if (ifp->if_flags & XFS_IFBROOT) { cur = xfs_bmbt_init_cursor(mp, tp, ip, whichfork); cur->bc_private.b.firstblock = *firstfsb; cur->bc_private.b.flist = free_list; cur->bc_private.b.flags = 0; error = xfs_bmbt_lookup_eq(cur, got.br_startoff, got.br_startblock, got.br_blockcount, &i); if (error) goto del_cursor; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, del_cursor); } xfs_bmbt_set_blockcount(gotp, gotblkcnt); got.br_blockcount = gotblkcnt; logflags = XFS_ILOG_CORE; if (cur) { error = xfs_bmbt_update(cur, got.br_startoff, got.br_startblock, got.br_blockcount, got.br_state); if (error) goto del_cursor; } else logflags |= XFS_ILOG_DEXT; /* Add new extent */ current_ext++; xfs_iext_insert(ip, current_ext, 1, &new, 0); XFS_IFORK_NEXT_SET(ip, whichfork, XFS_IFORK_NEXTENTS(ip, whichfork) + 1); if (cur) { error = xfs_bmbt_lookup_eq(cur, new.br_startoff, new.br_startblock, new.br_blockcount, &i); if (error) goto del_cursor; XFS_WANT_CORRUPTED_GOTO(mp, i == 0, del_cursor); cur->bc_rec.b.br_state = new.br_state; error = xfs_btree_insert(cur, &i); if (error) goto del_cursor; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, del_cursor); } /* * Convert to a btree if necessary. */ if (xfs_bmap_needs_btree(ip, whichfork)) { int tmp_logflags; /* partial log flag return val */ ASSERT(cur == NULL); error = xfs_bmap_extents_to_btree(tp, ip, firstfsb, free_list, &cur, 0, &tmp_logflags, whichfork); logflags |= tmp_logflags; } del_cursor: if (cur) { cur->bc_private.b.allocated = 0; xfs_btree_del_cursor(cur, error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR); } if (logflags) xfs_trans_log_inode(tp, ip, logflags); return error; } int xfs_bmap_split_extent( struct xfs_inode *ip, xfs_fileoff_t split_fsb) { struct xfs_mount *mp = ip->i_mount; struct xfs_trans *tp; struct xfs_bmap_free free_list; xfs_fsblock_t firstfsb; int committed; int error; tp = xfs_trans_alloc(mp, XFS_TRANS_DIOSTRAT); error = xfs_trans_reserve(tp, &M_RES(mp)->tr_write, XFS_DIOSTRAT_SPACE_RES(mp, 0), 0); if (error) { xfs_trans_cancel(tp); return error; } xfs_ilock(ip, XFS_ILOCK_EXCL); xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); xfs_bmap_init(&free_list, &firstfsb); error = xfs_bmap_split_extent_at(tp, ip, split_fsb, &firstfsb, &free_list); if (error) goto out; error = xfs_bmap_finish(&tp, &free_list, &committed); if (error) goto out; return xfs_trans_commit(tp); out: xfs_trans_cancel(tp); return error; } partclone-0.2.86/src/xfs/xfs_bmap.h000066400000000000000000000204361262102574200171430ustar00rootroot00000000000000/* * Copyright (c) 2000-2006 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __XFS_BMAP_H__ #define __XFS_BMAP_H__ struct getbmap; struct xfs_bmbt_irec; struct xfs_ifork; struct xfs_inode; struct xfs_mount; struct xfs_trans; extern kmem_zone_t *xfs_bmap_free_item_zone; /* * Argument structure for xfs_bmap_alloc. */ struct xfs_bmalloca { xfs_fsblock_t *firstblock; /* i/o first block allocated */ struct xfs_bmap_free *flist; /* bmap freelist */ struct xfs_trans *tp; /* transaction pointer */ struct xfs_inode *ip; /* incore inode pointer */ struct xfs_bmbt_irec prev; /* extent before the new one */ struct xfs_bmbt_irec got; /* extent after, or delayed */ xfs_fileoff_t offset; /* offset in file filling in */ xfs_extlen_t length; /* i/o length asked/allocated */ xfs_fsblock_t blkno; /* starting block of new extent */ struct xfs_btree_cur *cur; /* btree cursor */ xfs_extnum_t idx; /* current extent index */ int nallocs;/* number of extents alloc'd */ int logflags;/* flags for transaction logging */ xfs_extlen_t total; /* total blocks needed for xaction */ xfs_extlen_t minlen; /* minimum allocation size (blocks) */ xfs_extlen_t minleft; /* amount must be left after alloc */ bool eof; /* set if allocating past last extent */ bool wasdel; /* replacing a delayed allocation */ bool userdata;/* set if is user data */ bool aeof; /* allocated space at eof */ bool conv; /* overwriting unwritten extents */ int flags; }; /* * List of extents to be free "later". * The list is kept sorted on xbf_startblock. */ typedef struct xfs_bmap_free_item { xfs_fsblock_t xbfi_startblock;/* starting fs block number */ xfs_extlen_t xbfi_blockcount;/* number of blocks in extent */ struct xfs_bmap_free_item *xbfi_next; /* link to next entry */ } xfs_bmap_free_item_t; /* * Header for free extent list. * * xbf_low is used by the allocator to activate the lowspace algorithm - * when free space is running low the extent allocator may choose to * allocate an extent from an AG without leaving sufficient space for * a btree split when inserting the new extent. In this case the allocator * will enable the lowspace algorithm which is supposed to allow further * allocations (such as btree splits and newroots) to allocate from * sequential AGs. In order to avoid locking AGs out of order the lowspace * algorithm will start searching for free space from AG 0. If the correct * transaction reservations have been made then this algorithm will eventually * find all the space it needs. */ typedef struct xfs_bmap_free { xfs_bmap_free_item_t *xbf_first; /* list of to-be-free extents */ int xbf_count; /* count of items on list */ int xbf_low; /* alloc in low mode */ } xfs_bmap_free_t; #define XFS_BMAP_MAX_NMAP 4 /* * Flags for xfs_bmapi_* */ #define XFS_BMAPI_ENTIRE 0x001 /* return entire extent, not trimmed */ #define XFS_BMAPI_METADATA 0x002 /* mapping metadata not user data */ #define XFS_BMAPI_ATTRFORK 0x004 /* use attribute fork not data */ #define XFS_BMAPI_PREALLOC 0x008 /* preallocation op: unwritten space */ #define XFS_BMAPI_IGSTATE 0x010 /* Ignore state - */ /* combine contig. space */ #define XFS_BMAPI_CONTIG 0x020 /* must allocate only one extent */ /* * unwritten extent conversion - this needs write cache flushing and no additional * allocation alignments. When specified with XFS_BMAPI_PREALLOC it converts * from written to unwritten, otherwise convert from unwritten to written. */ #define XFS_BMAPI_CONVERT 0x040 #define XFS_BMAPI_FLAGS \ { XFS_BMAPI_ENTIRE, "ENTIRE" }, \ { XFS_BMAPI_METADATA, "METADATA" }, \ { XFS_BMAPI_ATTRFORK, "ATTRFORK" }, \ { XFS_BMAPI_PREALLOC, "PREALLOC" }, \ { XFS_BMAPI_IGSTATE, "IGSTATE" }, \ { XFS_BMAPI_CONTIG, "CONTIG" }, \ { XFS_BMAPI_CONVERT, "CONVERT" } static inline int xfs_bmapi_aflag(int w) { return (w == XFS_ATTR_FORK ? XFS_BMAPI_ATTRFORK : 0); } /* * Special values for xfs_bmbt_irec_t br_startblock field. */ #define DELAYSTARTBLOCK ((xfs_fsblock_t)-1LL) #define HOLESTARTBLOCK ((xfs_fsblock_t)-2LL) static inline void xfs_bmap_init(xfs_bmap_free_t *flp, xfs_fsblock_t *fbp) { ((flp)->xbf_first = NULL, (flp)->xbf_count = 0, \ (flp)->xbf_low = 0, *(fbp) = NULLFSBLOCK); } /* * Flags for xfs_bmap_add_extent*. */ #define BMAP_LEFT_CONTIG (1 << 0) #define BMAP_RIGHT_CONTIG (1 << 1) #define BMAP_LEFT_FILLING (1 << 2) #define BMAP_RIGHT_FILLING (1 << 3) #define BMAP_LEFT_DELAY (1 << 4) #define BMAP_RIGHT_DELAY (1 << 5) #define BMAP_LEFT_VALID (1 << 6) #define BMAP_RIGHT_VALID (1 << 7) #define BMAP_ATTRFORK (1 << 8) #define XFS_BMAP_EXT_FLAGS \ { BMAP_LEFT_CONTIG, "LC" }, \ { BMAP_RIGHT_CONTIG, "RC" }, \ { BMAP_LEFT_FILLING, "LF" }, \ { BMAP_RIGHT_FILLING, "RF" }, \ { BMAP_ATTRFORK, "ATTR" } /* * This macro is used to determine how many extents will be shifted * in one write transaction. We could require two splits, * an extent move on the first and an extent merge on the second, * So it is proper that one extent is shifted inside write transaction * at a time. */ #define XFS_BMAP_MAX_SHIFT_EXTENTS 1 enum shift_direction { SHIFT_LEFT = 0, SHIFT_RIGHT, }; #ifdef DEBUG void xfs_bmap_trace_exlist(struct xfs_inode *ip, xfs_extnum_t cnt, int whichfork, unsigned long caller_ip); #define XFS_BMAP_TRACE_EXLIST(ip,c,w) \ xfs_bmap_trace_exlist(ip,c,w, _THIS_IP_) #else #define XFS_BMAP_TRACE_EXLIST(ip,c,w) #endif int xfs_bmap_add_attrfork(struct xfs_inode *ip, int size, int rsvd); void xfs_bmap_local_to_extents_empty(struct xfs_inode *ip, int whichfork); void xfs_bmap_add_free(xfs_fsblock_t bno, xfs_filblks_t len, struct xfs_bmap_free *flist, struct xfs_mount *mp); void xfs_bmap_cancel(struct xfs_bmap_free *flist); int xfs_bmap_finish(struct xfs_trans **tp, struct xfs_bmap_free *flist, int *committed); void xfs_bmap_compute_maxlevels(struct xfs_mount *mp, int whichfork); int xfs_bmap_first_unused(struct xfs_trans *tp, struct xfs_inode *ip, xfs_extlen_t len, xfs_fileoff_t *unused, int whichfork); int xfs_bmap_last_before(struct xfs_trans *tp, struct xfs_inode *ip, xfs_fileoff_t *last_block, int whichfork); int xfs_bmap_last_offset(struct xfs_inode *ip, xfs_fileoff_t *unused, int whichfork); int xfs_bmap_one_block(struct xfs_inode *ip, int whichfork); int xfs_bmap_read_extents(struct xfs_trans *tp, struct xfs_inode *ip, int whichfork); int xfs_bmapi_read(struct xfs_inode *ip, xfs_fileoff_t bno, xfs_filblks_t len, struct xfs_bmbt_irec *mval, int *nmap, int flags); int xfs_bmapi_delay(struct xfs_inode *ip, xfs_fileoff_t bno, xfs_filblks_t len, struct xfs_bmbt_irec *mval, int *nmap, int flags); int xfs_bmapi_write(struct xfs_trans *tp, struct xfs_inode *ip, xfs_fileoff_t bno, xfs_filblks_t len, int flags, xfs_fsblock_t *firstblock, xfs_extlen_t total, struct xfs_bmbt_irec *mval, int *nmap, struct xfs_bmap_free *flist); int xfs_bunmapi(struct xfs_trans *tp, struct xfs_inode *ip, xfs_fileoff_t bno, xfs_filblks_t len, int flags, xfs_extnum_t nexts, xfs_fsblock_t *firstblock, struct xfs_bmap_free *flist, int *done); int xfs_check_nostate_extents(struct xfs_ifork *ifp, xfs_extnum_t idx, xfs_extnum_t num); uint xfs_default_attroffset(struct xfs_inode *ip); int xfs_bmap_shift_extents(struct xfs_trans *tp, struct xfs_inode *ip, xfs_fileoff_t *next_fsb, xfs_fileoff_t offset_shift_fsb, int *done, xfs_fileoff_t stop_fsb, xfs_fsblock_t *firstblock, struct xfs_bmap_free *flist, enum shift_direction direction, int num_exts); int xfs_bmap_split_extent(struct xfs_inode *ip, xfs_fileoff_t split_offset); struct xfs_bmbt_rec_host * xfs_bmap_search_extents(struct xfs_inode *ip, xfs_fileoff_t bno, int fork, int *eofp, xfs_extnum_t *lastxp, struct xfs_bmbt_irec *gotp, struct xfs_bmbt_irec *prevp); #endif /* __XFS_BMAP_H__ */ partclone-0.2.86/src/xfs/xfs_bmap_btree.c000066400000000000000000000544761262102574200203320ustar00rootroot00000000000000/* * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_bit.h" #include "xfs_mount.h" #include "xfs_inode.h" #include "xfs_trans.h" #include "xfs_alloc.h" #include "xfs_btree.h" #include "xfs_bmap_btree.h" #include "xfs_bmap.h" #include "xfs_trace.h" #include "xfs_cksum.h" /* * Determine the extent state. */ /* ARGSUSED */ STATIC xfs_exntst_t xfs_extent_state( xfs_filblks_t blks, int extent_flag) { if (extent_flag) { ASSERT(blks != 0); /* saved for DMIG */ return XFS_EXT_UNWRITTEN; } return XFS_EXT_NORM; } /* * Convert on-disk form of btree root to in-memory form. */ void xfs_bmdr_to_bmbt( struct xfs_inode *ip, xfs_bmdr_block_t *dblock, int dblocklen, struct xfs_btree_block *rblock, int rblocklen) { struct xfs_mount *mp = ip->i_mount; int dmxr; xfs_bmbt_key_t *fkp; __be64 *fpp; xfs_bmbt_key_t *tkp; __be64 *tpp; if (xfs_sb_version_hascrc(&mp->m_sb)) xfs_btree_init_block_int(mp, rblock, XFS_BUF_DADDR_NULL, XFS_BMAP_CRC_MAGIC, 0, 0, ip->i_ino, XFS_BTREE_LONG_PTRS | XFS_BTREE_CRC_BLOCKS); else xfs_btree_init_block_int(mp, rblock, XFS_BUF_DADDR_NULL, XFS_BMAP_MAGIC, 0, 0, ip->i_ino, XFS_BTREE_LONG_PTRS); rblock->bb_level = dblock->bb_level; ASSERT(be16_to_cpu(rblock->bb_level) > 0); rblock->bb_numrecs = dblock->bb_numrecs; dmxr = xfs_bmdr_maxrecs(dblocklen, 0); fkp = XFS_BMDR_KEY_ADDR(dblock, 1); tkp = XFS_BMBT_KEY_ADDR(mp, rblock, 1); fpp = XFS_BMDR_PTR_ADDR(dblock, 1, dmxr); tpp = XFS_BMAP_BROOT_PTR_ADDR(mp, rblock, 1, rblocklen); dmxr = be16_to_cpu(dblock->bb_numrecs); memcpy(tkp, fkp, sizeof(*fkp) * dmxr); memcpy(tpp, fpp, sizeof(*fpp) * dmxr); } /* * Convert a compressed bmap extent record to an uncompressed form. * This code must be in sync with the routines xfs_bmbt_get_startoff, * xfs_bmbt_get_startblock, xfs_bmbt_get_blockcount and xfs_bmbt_get_state. */ STATIC void __xfs_bmbt_get_all( __uint64_t l0, __uint64_t l1, xfs_bmbt_irec_t *s) { int ext_flag; xfs_exntst_t st; ext_flag = (int)(l0 >> (64 - BMBT_EXNTFLAG_BITLEN)); s->br_startoff = ((xfs_fileoff_t)l0 & xfs_mask64lo(64 - BMBT_EXNTFLAG_BITLEN)) >> 9; s->br_startblock = (((xfs_fsblock_t)l0 & xfs_mask64lo(9)) << 43) | (((xfs_fsblock_t)l1) >> 21); s->br_blockcount = (xfs_filblks_t)(l1 & xfs_mask64lo(21)); /* This is xfs_extent_state() in-line */ if (ext_flag) { ASSERT(s->br_blockcount != 0); /* saved for DMIG */ st = XFS_EXT_UNWRITTEN; } else st = XFS_EXT_NORM; s->br_state = st; } void xfs_bmbt_get_all( xfs_bmbt_rec_host_t *r, xfs_bmbt_irec_t *s) { __xfs_bmbt_get_all(r->l0, r->l1, s); } /* * Extract the blockcount field from an in memory bmap extent record. */ xfs_filblks_t xfs_bmbt_get_blockcount( xfs_bmbt_rec_host_t *r) { return (xfs_filblks_t)(r->l1 & xfs_mask64lo(21)); } /* * Extract the startblock field from an in memory bmap extent record. */ xfs_fsblock_t xfs_bmbt_get_startblock( xfs_bmbt_rec_host_t *r) { return (((xfs_fsblock_t)r->l0 & xfs_mask64lo(9)) << 43) | (((xfs_fsblock_t)r->l1) >> 21); } /* * Extract the startoff field from an in memory bmap extent record. */ xfs_fileoff_t xfs_bmbt_get_startoff( xfs_bmbt_rec_host_t *r) { return ((xfs_fileoff_t)r->l0 & xfs_mask64lo(64 - BMBT_EXNTFLAG_BITLEN)) >> 9; } xfs_exntst_t xfs_bmbt_get_state( xfs_bmbt_rec_host_t *r) { int ext_flag; ext_flag = (int)((r->l0) >> (64 - BMBT_EXNTFLAG_BITLEN)); return xfs_extent_state(xfs_bmbt_get_blockcount(r), ext_flag); } /* * Extract the blockcount field from an on disk bmap extent record. */ xfs_filblks_t xfs_bmbt_disk_get_blockcount( xfs_bmbt_rec_t *r) { return (xfs_filblks_t)(be64_to_cpu(r->l1) & xfs_mask64lo(21)); } /* * Extract the startoff field from a disk format bmap extent record. */ xfs_fileoff_t xfs_bmbt_disk_get_startoff( xfs_bmbt_rec_t *r) { return ((xfs_fileoff_t)be64_to_cpu(r->l0) & xfs_mask64lo(64 - BMBT_EXNTFLAG_BITLEN)) >> 9; } /* * Set all the fields in a bmap extent record from the arguments. */ void xfs_bmbt_set_allf( xfs_bmbt_rec_host_t *r, xfs_fileoff_t startoff, xfs_fsblock_t startblock, xfs_filblks_t blockcount, xfs_exntst_t state) { int extent_flag = (state == XFS_EXT_NORM) ? 0 : 1; ASSERT(state == XFS_EXT_NORM || state == XFS_EXT_UNWRITTEN); ASSERT((startoff & xfs_mask64hi(64-BMBT_STARTOFF_BITLEN)) == 0); ASSERT((blockcount & xfs_mask64hi(64-BMBT_BLOCKCOUNT_BITLEN)) == 0); ASSERT((startblock & xfs_mask64hi(64-BMBT_STARTBLOCK_BITLEN)) == 0); r->l0 = ((xfs_bmbt_rec_base_t)extent_flag << 63) | ((xfs_bmbt_rec_base_t)startoff << 9) | ((xfs_bmbt_rec_base_t)startblock >> 43); r->l1 = ((xfs_bmbt_rec_base_t)startblock << 21) | ((xfs_bmbt_rec_base_t)blockcount & (xfs_bmbt_rec_base_t)xfs_mask64lo(21)); } /* * Set all the fields in a bmap extent record from the uncompressed form. */ void xfs_bmbt_set_all( xfs_bmbt_rec_host_t *r, xfs_bmbt_irec_t *s) { xfs_bmbt_set_allf(r, s->br_startoff, s->br_startblock, s->br_blockcount, s->br_state); } /* * Set all the fields in a disk format bmap extent record from the arguments. */ void xfs_bmbt_disk_set_allf( xfs_bmbt_rec_t *r, xfs_fileoff_t startoff, xfs_fsblock_t startblock, xfs_filblks_t blockcount, xfs_exntst_t state) { int extent_flag = (state == XFS_EXT_NORM) ? 0 : 1; ASSERT(state == XFS_EXT_NORM || state == XFS_EXT_UNWRITTEN); ASSERT((startoff & xfs_mask64hi(64-BMBT_STARTOFF_BITLEN)) == 0); ASSERT((blockcount & xfs_mask64hi(64-BMBT_BLOCKCOUNT_BITLEN)) == 0); ASSERT((startblock & xfs_mask64hi(64-BMBT_STARTBLOCK_BITLEN)) == 0); r->l0 = cpu_to_be64( ((xfs_bmbt_rec_base_t)extent_flag << 63) | ((xfs_bmbt_rec_base_t)startoff << 9) | ((xfs_bmbt_rec_base_t)startblock >> 43)); r->l1 = cpu_to_be64( ((xfs_bmbt_rec_base_t)startblock << 21) | ((xfs_bmbt_rec_base_t)blockcount & (xfs_bmbt_rec_base_t)xfs_mask64lo(21))); } /* * Set all the fields in a bmap extent record from the uncompressed form. */ STATIC void xfs_bmbt_disk_set_all( xfs_bmbt_rec_t *r, xfs_bmbt_irec_t *s) { xfs_bmbt_disk_set_allf(r, s->br_startoff, s->br_startblock, s->br_blockcount, s->br_state); } /* * Set the blockcount field in a bmap extent record. */ void xfs_bmbt_set_blockcount( xfs_bmbt_rec_host_t *r, xfs_filblks_t v) { ASSERT((v & xfs_mask64hi(43)) == 0); r->l1 = (r->l1 & (xfs_bmbt_rec_base_t)xfs_mask64hi(43)) | (xfs_bmbt_rec_base_t)(v & xfs_mask64lo(21)); } /* * Set the startblock field in a bmap extent record. */ void xfs_bmbt_set_startblock( xfs_bmbt_rec_host_t *r, xfs_fsblock_t v) { ASSERT((v & xfs_mask64hi(12)) == 0); r->l0 = (r->l0 & (xfs_bmbt_rec_base_t)xfs_mask64hi(55)) | (xfs_bmbt_rec_base_t)(v >> 43); r->l1 = (r->l1 & (xfs_bmbt_rec_base_t)xfs_mask64lo(21)) | (xfs_bmbt_rec_base_t)(v << 21); } /* * Set the startoff field in a bmap extent record. */ void xfs_bmbt_set_startoff( xfs_bmbt_rec_host_t *r, xfs_fileoff_t v) { ASSERT((v & xfs_mask64hi(9)) == 0); r->l0 = (r->l0 & (xfs_bmbt_rec_base_t) xfs_mask64hi(1)) | ((xfs_bmbt_rec_base_t)v << 9) | (r->l0 & (xfs_bmbt_rec_base_t)xfs_mask64lo(9)); } /* * Set the extent state field in a bmap extent record. */ void xfs_bmbt_set_state( xfs_bmbt_rec_host_t *r, xfs_exntst_t v) { ASSERT(v == XFS_EXT_NORM || v == XFS_EXT_UNWRITTEN); if (v == XFS_EXT_NORM) r->l0 &= xfs_mask64lo(64 - BMBT_EXNTFLAG_BITLEN); else r->l0 |= xfs_mask64hi(BMBT_EXNTFLAG_BITLEN); } /* * Convert in-memory form of btree root to on-disk form. */ void xfs_bmbt_to_bmdr( struct xfs_mount *mp, struct xfs_btree_block *rblock, int rblocklen, xfs_bmdr_block_t *dblock, int dblocklen) { int dmxr; xfs_bmbt_key_t *fkp; __be64 *fpp; xfs_bmbt_key_t *tkp; __be64 *tpp; if (xfs_sb_version_hascrc(&mp->m_sb)) { ASSERT(rblock->bb_magic == cpu_to_be32(XFS_BMAP_CRC_MAGIC)); ASSERT(uuid_equal(&rblock->bb_u.l.bb_uuid, &mp->m_sb.sb_meta_uuid)); ASSERT(rblock->bb_u.l.bb_blkno == cpu_to_be64(XFS_BUF_DADDR_NULL)); } else ASSERT(rblock->bb_magic == cpu_to_be32(XFS_BMAP_MAGIC)); ASSERT(rblock->bb_u.l.bb_leftsib == cpu_to_be64(NULLFSBLOCK)); ASSERT(rblock->bb_u.l.bb_rightsib == cpu_to_be64(NULLFSBLOCK)); ASSERT(rblock->bb_level != 0); dblock->bb_level = rblock->bb_level; dblock->bb_numrecs = rblock->bb_numrecs; dmxr = xfs_bmdr_maxrecs(dblocklen, 0); fkp = XFS_BMBT_KEY_ADDR(mp, rblock, 1); tkp = XFS_BMDR_KEY_ADDR(dblock, 1); fpp = XFS_BMAP_BROOT_PTR_ADDR(mp, rblock, 1, rblocklen); tpp = XFS_BMDR_PTR_ADDR(dblock, 1, dmxr); dmxr = be16_to_cpu(dblock->bb_numrecs); memcpy(tkp, fkp, sizeof(*fkp) * dmxr); memcpy(tpp, fpp, sizeof(*fpp) * dmxr); } /* * Check extent records, which have just been read, for * any bit in the extent flag field. ASSERT on debug * kernels, as this condition should not occur. * Return an error condition (1) if any flags found, * otherwise return 0. */ int xfs_check_nostate_extents( xfs_ifork_t *ifp, xfs_extnum_t idx, xfs_extnum_t num) { for (; num > 0; num--, idx++) { xfs_bmbt_rec_host_t *ep = xfs_iext_get_ext(ifp, idx); if ((ep->l0 >> (64 - BMBT_EXNTFLAG_BITLEN)) != 0) { ASSERT(0); return 1; } } return 0; } STATIC struct xfs_btree_cur * xfs_bmbt_dup_cursor( struct xfs_btree_cur *cur) { struct xfs_btree_cur *new; new = xfs_bmbt_init_cursor(cur->bc_mp, cur->bc_tp, cur->bc_private.b.ip, cur->bc_private.b.whichfork); /* * Copy the firstblock, flist, and flags values, * since init cursor doesn't get them. */ new->bc_private.b.firstblock = cur->bc_private.b.firstblock; new->bc_private.b.flist = cur->bc_private.b.flist; new->bc_private.b.flags = cur->bc_private.b.flags; return new; } STATIC void xfs_bmbt_update_cursor( struct xfs_btree_cur *src, struct xfs_btree_cur *dst) { ASSERT((dst->bc_private.b.firstblock != NULLFSBLOCK) || (dst->bc_private.b.ip->i_d.di_flags & XFS_DIFLAG_REALTIME)); ASSERT(dst->bc_private.b.flist == src->bc_private.b.flist); dst->bc_private.b.allocated += src->bc_private.b.allocated; dst->bc_private.b.firstblock = src->bc_private.b.firstblock; src->bc_private.b.allocated = 0; } STATIC int xfs_bmbt_alloc_block( struct xfs_btree_cur *cur, union xfs_btree_ptr *start, union xfs_btree_ptr *new, int *stat) { xfs_alloc_arg_t args; /* block allocation args */ int error; /* error return value */ memset(&args, 0, sizeof(args)); args.tp = cur->bc_tp; args.mp = cur->bc_mp; args.fsbno = cur->bc_private.b.firstblock; args.firstblock = args.fsbno; if (args.fsbno == NULLFSBLOCK) { args.fsbno = be64_to_cpu(start->l); args.type = XFS_ALLOCTYPE_START_BNO; /* * Make sure there is sufficient room left in the AG to * complete a full tree split for an extent insert. If * we are converting the middle part of an extent then * we may need space for two tree splits. * * We are relying on the caller to make the correct block * reservation for this operation to succeed. If the * reservation amount is insufficient then we may fail a * block allocation here and corrupt the filesystem. */ args.minleft = xfs_trans_get_block_res(args.tp); } else if (cur->bc_private.b.flist->xbf_low) { args.type = XFS_ALLOCTYPE_START_BNO; } else { args.type = XFS_ALLOCTYPE_NEAR_BNO; } args.minlen = args.maxlen = args.prod = 1; args.wasdel = cur->bc_private.b.flags & XFS_BTCUR_BPRV_WASDEL; if (!args.wasdel && xfs_trans_get_block_res(args.tp) == 0) { error = -ENOSPC; goto error0; } error = xfs_alloc_vextent(&args); if (error) goto error0; if (args.fsbno == NULLFSBLOCK && args.minleft) { /* * Could not find an AG with enough free space to satisfy * a full btree split. Try again without minleft and if * successful activate the lowspace algorithm. */ args.fsbno = 0; args.type = XFS_ALLOCTYPE_FIRST_AG; args.minleft = 0; error = xfs_alloc_vextent(&args); if (error) goto error0; cur->bc_private.b.flist->xbf_low = 1; } if (args.fsbno == NULLFSBLOCK) { XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); *stat = 0; return 0; } ASSERT(args.len == 1); cur->bc_private.b.firstblock = args.fsbno; cur->bc_private.b.allocated++; cur->bc_private.b.ip->i_d.di_nblocks++; xfs_trans_log_inode(args.tp, cur->bc_private.b.ip, XFS_ILOG_CORE); xfs_trans_mod_dquot_byino(args.tp, cur->bc_private.b.ip, XFS_TRANS_DQ_BCOUNT, 1L); new->l = cpu_to_be64(args.fsbno); XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); *stat = 1; return 0; error0: XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR); return error; } STATIC int xfs_bmbt_free_block( struct xfs_btree_cur *cur, struct xfs_buf *bp) { struct xfs_mount *mp = cur->bc_mp; struct xfs_inode *ip = cur->bc_private.b.ip; struct xfs_trans *tp = cur->bc_tp; xfs_fsblock_t fsbno = XFS_DADDR_TO_FSB(mp, XFS_BUF_ADDR(bp)); xfs_bmap_add_free(fsbno, 1, cur->bc_private.b.flist, mp); ip->i_d.di_nblocks--; xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_BCOUNT, -1L); xfs_trans_binval(tp, bp); return 0; } STATIC int xfs_bmbt_get_minrecs( struct xfs_btree_cur *cur, int level) { if (level == cur->bc_nlevels - 1) { struct xfs_ifork *ifp; ifp = XFS_IFORK_PTR(cur->bc_private.b.ip, cur->bc_private.b.whichfork); return xfs_bmbt_maxrecs(cur->bc_mp, ifp->if_broot_bytes, level == 0) / 2; } return cur->bc_mp->m_bmap_dmnr[level != 0]; } int xfs_bmbt_get_maxrecs( struct xfs_btree_cur *cur, int level) { if (level == cur->bc_nlevels - 1) { struct xfs_ifork *ifp; ifp = XFS_IFORK_PTR(cur->bc_private.b.ip, cur->bc_private.b.whichfork); return xfs_bmbt_maxrecs(cur->bc_mp, ifp->if_broot_bytes, level == 0); } return cur->bc_mp->m_bmap_dmxr[level != 0]; } /* * Get the maximum records we could store in the on-disk format. * * For non-root nodes this is equivalent to xfs_bmbt_get_maxrecs, but * for the root node this checks the available space in the dinode fork * so that we can resize the in-memory buffer to match it. After a * resize to the maximum size this function returns the same value * as xfs_bmbt_get_maxrecs for the root node, too. */ STATIC int xfs_bmbt_get_dmaxrecs( struct xfs_btree_cur *cur, int level) { if (level != cur->bc_nlevels - 1) return cur->bc_mp->m_bmap_dmxr[level != 0]; return xfs_bmdr_maxrecs(cur->bc_private.b.forksize, level == 0); } STATIC void xfs_bmbt_init_key_from_rec( union xfs_btree_key *key, union xfs_btree_rec *rec) { key->bmbt.br_startoff = cpu_to_be64(xfs_bmbt_disk_get_startoff(&rec->bmbt)); } STATIC void xfs_bmbt_init_rec_from_key( union xfs_btree_key *key, union xfs_btree_rec *rec) { ASSERT(key->bmbt.br_startoff != 0); xfs_bmbt_disk_set_allf(&rec->bmbt, be64_to_cpu(key->bmbt.br_startoff), 0, 0, XFS_EXT_NORM); } STATIC void xfs_bmbt_init_rec_from_cur( struct xfs_btree_cur *cur, union xfs_btree_rec *rec) { xfs_bmbt_disk_set_all(&rec->bmbt, &cur->bc_rec.b); } STATIC void xfs_bmbt_init_ptr_from_cur( struct xfs_btree_cur *cur, union xfs_btree_ptr *ptr) { ptr->l = 0; } STATIC __int64_t xfs_bmbt_key_diff( struct xfs_btree_cur *cur, union xfs_btree_key *key) { return (__int64_t)be64_to_cpu(key->bmbt.br_startoff) - cur->bc_rec.b.br_startoff; } static bool xfs_bmbt_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_target->bt_mount; struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); unsigned int level; switch (block->bb_magic) { case cpu_to_be32(XFS_BMAP_CRC_MAGIC): if (!xfs_sb_version_hascrc(&mp->m_sb)) return false; if (!uuid_equal(&block->bb_u.l.bb_uuid, &mp->m_sb.sb_meta_uuid)) return false; if (be64_to_cpu(block->bb_u.l.bb_blkno) != bp->b_bn) return false; /* * XXX: need a better way of verifying the owner here. Right now * just make sure there has been one set. */ if (be64_to_cpu(block->bb_u.l.bb_owner) == 0) return false; /* fall through */ case cpu_to_be32(XFS_BMAP_MAGIC): break; default: return false; } /* * numrecs and level verification. * * We don't know what fork we belong to, so just verify that the level * is less than the maximum of the two. Later checks will be more * precise. */ level = be16_to_cpu(block->bb_level); if (level > max(mp->m_bm_maxlevels[0], mp->m_bm_maxlevels[1])) return false; if (be16_to_cpu(block->bb_numrecs) > mp->m_bmap_dmxr[level != 0]) return false; /* sibling pointer verification */ if (!block->bb_u.l.bb_leftsib || (block->bb_u.l.bb_leftsib != cpu_to_be64(NULLFSBLOCK) && !XFS_FSB_SANITY_CHECK(mp, be64_to_cpu(block->bb_u.l.bb_leftsib)))) return false; if (!block->bb_u.l.bb_rightsib || (block->bb_u.l.bb_rightsib != cpu_to_be64(NULLFSBLOCK) && !XFS_FSB_SANITY_CHECK(mp, be64_to_cpu(block->bb_u.l.bb_rightsib)))) return false; return true; } static void xfs_bmbt_read_verify( struct xfs_buf *bp) { if (!xfs_btree_lblock_verify_crc(bp)) xfs_buf_ioerror(bp, -EFSBADCRC); else if (!xfs_bmbt_verify(bp)) xfs_buf_ioerror(bp, -EFSCORRUPTED); if (bp->b_error) { trace_xfs_btree_corrupt(bp, _RET_IP_); xfs_verifier_error(bp); } } static void xfs_bmbt_write_verify( struct xfs_buf *bp) { if (!xfs_bmbt_verify(bp)) { trace_xfs_btree_corrupt(bp, _RET_IP_); xfs_buf_ioerror(bp, -EFSCORRUPTED); xfs_verifier_error(bp); return; } xfs_btree_lblock_calc_crc(bp); } const struct xfs_buf_ops xfs_bmbt_buf_ops = { .verify_read = xfs_bmbt_read_verify, .verify_write = xfs_bmbt_write_verify, }; #if defined(DEBUG) || defined(XFS_WARN) STATIC int xfs_bmbt_keys_inorder( struct xfs_btree_cur *cur, union xfs_btree_key *k1, union xfs_btree_key *k2) { return be64_to_cpu(k1->bmbt.br_startoff) < be64_to_cpu(k2->bmbt.br_startoff); } STATIC int xfs_bmbt_recs_inorder( struct xfs_btree_cur *cur, union xfs_btree_rec *r1, union xfs_btree_rec *r2) { return xfs_bmbt_disk_get_startoff(&r1->bmbt) + xfs_bmbt_disk_get_blockcount(&r1->bmbt) <= xfs_bmbt_disk_get_startoff(&r2->bmbt); } #endif /* DEBUG */ static const struct xfs_btree_ops xfs_bmbt_ops = { .rec_len = sizeof(xfs_bmbt_rec_t), .key_len = sizeof(xfs_bmbt_key_t), .dup_cursor = xfs_bmbt_dup_cursor, .update_cursor = xfs_bmbt_update_cursor, .alloc_block = xfs_bmbt_alloc_block, .free_block = xfs_bmbt_free_block, .get_maxrecs = xfs_bmbt_get_maxrecs, .get_minrecs = xfs_bmbt_get_minrecs, .get_dmaxrecs = xfs_bmbt_get_dmaxrecs, .init_key_from_rec = xfs_bmbt_init_key_from_rec, .init_rec_from_key = xfs_bmbt_init_rec_from_key, .init_rec_from_cur = xfs_bmbt_init_rec_from_cur, .init_ptr_from_cur = xfs_bmbt_init_ptr_from_cur, .key_diff = xfs_bmbt_key_diff, .buf_ops = &xfs_bmbt_buf_ops, #if defined(DEBUG) || defined(XFS_WARN) .keys_inorder = xfs_bmbt_keys_inorder, .recs_inorder = xfs_bmbt_recs_inorder, #endif }; /* * Allocate a new bmap btree cursor. */ struct xfs_btree_cur * /* new bmap btree cursor */ xfs_bmbt_init_cursor( struct xfs_mount *mp, /* file system mount point */ struct xfs_trans *tp, /* transaction pointer */ struct xfs_inode *ip, /* inode owning the btree */ int whichfork) /* data or attr fork */ { struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, whichfork); struct xfs_btree_cur *cur; cur = kmem_zone_zalloc(xfs_btree_cur_zone, KM_SLEEP); cur->bc_tp = tp; cur->bc_mp = mp; cur->bc_nlevels = be16_to_cpu(ifp->if_broot->bb_level) + 1; cur->bc_btnum = XFS_BTNUM_BMAP; cur->bc_blocklog = mp->m_sb.sb_blocklog; cur->bc_ops = &xfs_bmbt_ops; cur->bc_flags = XFS_BTREE_LONG_PTRS | XFS_BTREE_ROOT_IN_INODE; if (xfs_sb_version_hascrc(&mp->m_sb)) cur->bc_flags |= XFS_BTREE_CRC_BLOCKS; cur->bc_private.b.forksize = XFS_IFORK_SIZE(ip, whichfork); cur->bc_private.b.ip = ip; cur->bc_private.b.firstblock = NULLFSBLOCK; cur->bc_private.b.flist = NULL; cur->bc_private.b.allocated = 0; cur->bc_private.b.flags = 0; cur->bc_private.b.whichfork = whichfork; return cur; } /* * Calculate number of records in a bmap btree block. */ int xfs_bmbt_maxrecs( struct xfs_mount *mp, int blocklen, int leaf) { blocklen -= XFS_BMBT_BLOCK_LEN(mp); if (leaf) return blocklen / sizeof(xfs_bmbt_rec_t); return blocklen / (sizeof(xfs_bmbt_key_t) + sizeof(xfs_bmbt_ptr_t)); } /* * Calculate number of records in a bmap btree inode root. */ int xfs_bmdr_maxrecs( int blocklen, int leaf) { blocklen -= sizeof(xfs_bmdr_block_t); if (leaf) return blocklen / sizeof(xfs_bmdr_rec_t); return blocklen / (sizeof(xfs_bmdr_key_t) + sizeof(xfs_bmdr_ptr_t)); } /* * Change the owner of a btree format fork fo the inode passed in. Change it to * the owner of that is passed in so that we can change owners before or after * we switch forks between inodes. The operation that the caller is doing will * determine whether is needs to change owner before or after the switch. * * For demand paged transactional modification, the fork switch should be done * after reading in all the blocks, modifying them and pinning them in the * transaction. For modification when the buffers are already pinned in memory, * the fork switch can be done before changing the owner as we won't need to * validate the owner until the btree buffers are unpinned and writes can occur * again. * * For recovery based ownership change, there is no transactional context and * so a buffer list must be supplied so that we can record the buffers that we * modified for the caller to issue IO on. */ int xfs_bmbt_change_owner( struct xfs_trans *tp, struct xfs_inode *ip, int whichfork, xfs_ino_t new_owner, struct list_head *buffer_list) { struct xfs_btree_cur *cur; int error; ASSERT(tp || buffer_list); ASSERT(!(tp && buffer_list)); if (whichfork == XFS_DATA_FORK) ASSERT(ip->i_d.di_format == XFS_DINODE_FMT_BTREE); else ASSERT(ip->i_d.di_aformat == XFS_DINODE_FMT_BTREE); cur = xfs_bmbt_init_cursor(ip->i_mount, tp, ip, whichfork); if (!cur) return -ENOMEM; error = xfs_btree_change_owner(cur, new_owner, buffer_list); xfs_btree_del_cursor(cur, error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR); return error; } partclone-0.2.86/src/xfs/xfs_bmap_btree.h000066400000000000000000000120071262102574200203170ustar00rootroot00000000000000/* * Copyright (c) 2000,2002-2005 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __XFS_BMAP_BTREE_H__ #define __XFS_BMAP_BTREE_H__ struct xfs_btree_cur; struct xfs_btree_block; struct xfs_mount; struct xfs_inode; struct xfs_trans; /* * Extent state and extent format macros. */ #define XFS_EXTFMT_INODE(x) \ (xfs_sb_version_hasextflgbit(&((x)->i_mount->m_sb)) ? \ XFS_EXTFMT_HASSTATE : XFS_EXTFMT_NOSTATE) #define ISUNWRITTEN(x) ((x)->br_state == XFS_EXT_UNWRITTEN) /* * Btree block header size depends on a superblock flag. */ #define XFS_BMBT_BLOCK_LEN(mp) \ (xfs_sb_version_hascrc(&((mp)->m_sb)) ? \ XFS_BTREE_LBLOCK_CRC_LEN : XFS_BTREE_LBLOCK_LEN) #define XFS_BMBT_REC_ADDR(mp, block, index) \ ((xfs_bmbt_rec_t *) \ ((char *)(block) + \ XFS_BMBT_BLOCK_LEN(mp) + \ ((index) - 1) * sizeof(xfs_bmbt_rec_t))) #define XFS_BMBT_KEY_ADDR(mp, block, index) \ ((xfs_bmbt_key_t *) \ ((char *)(block) + \ XFS_BMBT_BLOCK_LEN(mp) + \ ((index) - 1) * sizeof(xfs_bmbt_key_t))) #define XFS_BMBT_PTR_ADDR(mp, block, index, maxrecs) \ ((xfs_bmbt_ptr_t *) \ ((char *)(block) + \ XFS_BMBT_BLOCK_LEN(mp) + \ (maxrecs) * sizeof(xfs_bmbt_key_t) + \ ((index) - 1) * sizeof(xfs_bmbt_ptr_t))) #define XFS_BMDR_REC_ADDR(block, index) \ ((xfs_bmdr_rec_t *) \ ((char *)(block) + \ sizeof(struct xfs_bmdr_block) + \ ((index) - 1) * sizeof(xfs_bmdr_rec_t))) #define XFS_BMDR_KEY_ADDR(block, index) \ ((xfs_bmdr_key_t *) \ ((char *)(block) + \ sizeof(struct xfs_bmdr_block) + \ ((index) - 1) * sizeof(xfs_bmdr_key_t))) #define XFS_BMDR_PTR_ADDR(block, index, maxrecs) \ ((xfs_bmdr_ptr_t *) \ ((char *)(block) + \ sizeof(struct xfs_bmdr_block) + \ (maxrecs) * sizeof(xfs_bmdr_key_t) + \ ((index) - 1) * sizeof(xfs_bmdr_ptr_t))) /* * These are to be used when we know the size of the block and * we don't have a cursor. */ #define XFS_BMAP_BROOT_PTR_ADDR(mp, bb, i, sz) \ XFS_BMBT_PTR_ADDR(mp, bb, i, xfs_bmbt_maxrecs(mp, sz, 0)) #define XFS_BMAP_BROOT_SPACE_CALC(mp, nrecs) \ (int)(XFS_BMBT_BLOCK_LEN(mp) + \ ((nrecs) * (sizeof(xfs_bmbt_key_t) + sizeof(xfs_bmbt_ptr_t)))) #define XFS_BMAP_BROOT_SPACE(mp, bb) \ (XFS_BMAP_BROOT_SPACE_CALC(mp, be16_to_cpu((bb)->bb_numrecs))) #define XFS_BMDR_SPACE_CALC(nrecs) \ (int)(sizeof(xfs_bmdr_block_t) + \ ((nrecs) * (sizeof(xfs_bmbt_key_t) + sizeof(xfs_bmbt_ptr_t)))) #define XFS_BMAP_BMDR_SPACE(bb) \ (XFS_BMDR_SPACE_CALC(be16_to_cpu((bb)->bb_numrecs))) /* * Maximum number of bmap btree levels. */ #define XFS_BM_MAXLEVELS(mp,w) ((mp)->m_bm_maxlevels[(w)]) /* * Prototypes for xfs_bmap.c to call. */ extern void xfs_bmdr_to_bmbt(struct xfs_inode *, xfs_bmdr_block_t *, int, struct xfs_btree_block *, int); extern void xfs_bmbt_get_all(xfs_bmbt_rec_host_t *r, xfs_bmbt_irec_t *s); extern xfs_filblks_t xfs_bmbt_get_blockcount(xfs_bmbt_rec_host_t *r); extern xfs_fsblock_t xfs_bmbt_get_startblock(xfs_bmbt_rec_host_t *r); extern xfs_fileoff_t xfs_bmbt_get_startoff(xfs_bmbt_rec_host_t *r); extern xfs_exntst_t xfs_bmbt_get_state(xfs_bmbt_rec_host_t *r); extern xfs_filblks_t xfs_bmbt_disk_get_blockcount(xfs_bmbt_rec_t *r); extern xfs_fileoff_t xfs_bmbt_disk_get_startoff(xfs_bmbt_rec_t *r); extern void xfs_bmbt_set_all(xfs_bmbt_rec_host_t *r, xfs_bmbt_irec_t *s); extern void xfs_bmbt_set_allf(xfs_bmbt_rec_host_t *r, xfs_fileoff_t o, xfs_fsblock_t b, xfs_filblks_t c, xfs_exntst_t v); extern void xfs_bmbt_set_blockcount(xfs_bmbt_rec_host_t *r, xfs_filblks_t v); extern void xfs_bmbt_set_startblock(xfs_bmbt_rec_host_t *r, xfs_fsblock_t v); extern void xfs_bmbt_set_startoff(xfs_bmbt_rec_host_t *r, xfs_fileoff_t v); extern void xfs_bmbt_set_state(xfs_bmbt_rec_host_t *r, xfs_exntst_t v); extern void xfs_bmbt_disk_set_allf(xfs_bmbt_rec_t *r, xfs_fileoff_t o, xfs_fsblock_t b, xfs_filblks_t c, xfs_exntst_t v); extern void xfs_bmbt_to_bmdr(struct xfs_mount *, struct xfs_btree_block *, int, xfs_bmdr_block_t *, int); extern int xfs_bmbt_get_maxrecs(struct xfs_btree_cur *, int level); extern int xfs_bmdr_maxrecs(int blocklen, int leaf); extern int xfs_bmbt_maxrecs(struct xfs_mount *, int blocklen, int leaf); extern int xfs_bmbt_change_owner(struct xfs_trans *tp, struct xfs_inode *ip, int whichfork, xfs_ino_t new_owner, struct list_head *buffer_list); extern struct xfs_btree_cur *xfs_bmbt_init_cursor(struct xfs_mount *, struct xfs_trans *, struct xfs_inode *, int); #endif /* __XFS_BMAP_BTREE_H__ */ partclone-0.2.86/src/xfs/xfs_btree.c000066400000000000000000003231661262102574200173260ustar00rootroot00000000000000/* * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_bit.h" #include "xfs_mount.h" #include "xfs_inode.h" #include "xfs_trans.h" #include "xfs_btree.h" #include "xfs_trace.h" #include "xfs_cksum.h" #include "xfs_alloc.h" /* * Cursor allocation zone. */ kmem_zone_t *xfs_btree_cur_zone; /* * Btree magic numbers. */ static const __uint32_t xfs_magics[2][XFS_BTNUM_MAX] = { { XFS_ABTB_MAGIC, XFS_ABTC_MAGIC, XFS_BMAP_MAGIC, XFS_IBT_MAGIC, XFS_FIBT_MAGIC }, { XFS_ABTB_CRC_MAGIC, XFS_ABTC_CRC_MAGIC, XFS_BMAP_CRC_MAGIC, XFS_IBT_CRC_MAGIC, XFS_FIBT_CRC_MAGIC } }; #define xfs_btree_magic(cur) \ xfs_magics[!!((cur)->bc_flags & XFS_BTREE_CRC_BLOCKS)][cur->bc_btnum] STATIC int /* error (0 or EFSCORRUPTED) */ xfs_btree_check_lblock( struct xfs_btree_cur *cur, /* btree cursor */ struct xfs_btree_block *block, /* btree long form block pointer */ int level, /* level of the btree block */ struct xfs_buf *bp) /* buffer for block, if any */ { int lblock_ok = 1; /* block passes checks */ struct xfs_mount *mp; /* file system mount point */ mp = cur->bc_mp; if (xfs_sb_version_hascrc(&mp->m_sb)) { lblock_ok = lblock_ok && uuid_equal(&block->bb_u.l.bb_uuid, &mp->m_sb.sb_meta_uuid) && block->bb_u.l.bb_blkno == cpu_to_be64( bp ? bp->b_bn : XFS_BUF_DADDR_NULL); } lblock_ok = lblock_ok && be32_to_cpu(block->bb_magic) == xfs_btree_magic(cur) && be16_to_cpu(block->bb_level) == level && be16_to_cpu(block->bb_numrecs) <= cur->bc_ops->get_maxrecs(cur, level) && block->bb_u.l.bb_leftsib && (block->bb_u.l.bb_leftsib == cpu_to_be64(NULLFSBLOCK) || XFS_FSB_SANITY_CHECK(mp, be64_to_cpu(block->bb_u.l.bb_leftsib))) && block->bb_u.l.bb_rightsib && (block->bb_u.l.bb_rightsib == cpu_to_be64(NULLFSBLOCK) || XFS_FSB_SANITY_CHECK(mp, be64_to_cpu(block->bb_u.l.bb_rightsib))); if (unlikely(XFS_TEST_ERROR(!lblock_ok, mp, XFS_ERRTAG_BTREE_CHECK_LBLOCK, XFS_RANDOM_BTREE_CHECK_LBLOCK))) { if (bp) trace_xfs_btree_corrupt(bp, _RET_IP_); XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp); return -EFSCORRUPTED; } return 0; } STATIC int /* error (0 or EFSCORRUPTED) */ xfs_btree_check_sblock( struct xfs_btree_cur *cur, /* btree cursor */ struct xfs_btree_block *block, /* btree short form block pointer */ int level, /* level of the btree block */ struct xfs_buf *bp) /* buffer containing block */ { struct xfs_mount *mp; /* file system mount point */ struct xfs_buf *agbp; /* buffer for ag. freespace struct */ struct xfs_agf *agf; /* ag. freespace structure */ xfs_agblock_t agflen; /* native ag. freespace length */ int sblock_ok = 1; /* block passes checks */ mp = cur->bc_mp; agbp = cur->bc_private.a.agbp; agf = XFS_BUF_TO_AGF(agbp); agflen = be32_to_cpu(agf->agf_length); if (xfs_sb_version_hascrc(&mp->m_sb)) { sblock_ok = sblock_ok && uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_meta_uuid) && block->bb_u.s.bb_blkno == cpu_to_be64( bp ? bp->b_bn : XFS_BUF_DADDR_NULL); } sblock_ok = sblock_ok && be32_to_cpu(block->bb_magic) == xfs_btree_magic(cur) && be16_to_cpu(block->bb_level) == level && be16_to_cpu(block->bb_numrecs) <= cur->bc_ops->get_maxrecs(cur, level) && (block->bb_u.s.bb_leftsib == cpu_to_be32(NULLAGBLOCK) || be32_to_cpu(block->bb_u.s.bb_leftsib) < agflen) && block->bb_u.s.bb_leftsib && (block->bb_u.s.bb_rightsib == cpu_to_be32(NULLAGBLOCK) || be32_to_cpu(block->bb_u.s.bb_rightsib) < agflen) && block->bb_u.s.bb_rightsib; if (unlikely(XFS_TEST_ERROR(!sblock_ok, mp, XFS_ERRTAG_BTREE_CHECK_SBLOCK, XFS_RANDOM_BTREE_CHECK_SBLOCK))) { if (bp) trace_xfs_btree_corrupt(bp, _RET_IP_); XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp); return -EFSCORRUPTED; } return 0; } /* * Debug routine: check that block header is ok. */ int xfs_btree_check_block( struct xfs_btree_cur *cur, /* btree cursor */ struct xfs_btree_block *block, /* generic btree block pointer */ int level, /* level of the btree block */ struct xfs_buf *bp) /* buffer containing block, if any */ { if (cur->bc_flags & XFS_BTREE_LONG_PTRS) return xfs_btree_check_lblock(cur, block, level, bp); else return xfs_btree_check_sblock(cur, block, level, bp); } /* * Check that (long) pointer is ok. */ int /* error (0 or EFSCORRUPTED) */ xfs_btree_check_lptr( struct xfs_btree_cur *cur, /* btree cursor */ xfs_fsblock_t bno, /* btree block disk address */ int level) /* btree block level */ { XFS_WANT_CORRUPTED_RETURN(cur->bc_mp, level > 0 && bno != NULLFSBLOCK && XFS_FSB_SANITY_CHECK(cur->bc_mp, bno)); return 0; } #ifdef DEBUG /* * Check that (short) pointer is ok. */ STATIC int /* error (0 or EFSCORRUPTED) */ xfs_btree_check_sptr( struct xfs_btree_cur *cur, /* btree cursor */ xfs_agblock_t bno, /* btree block disk address */ int level) /* btree block level */ { xfs_agblock_t agblocks = cur->bc_mp->m_sb.sb_agblocks; XFS_WANT_CORRUPTED_RETURN(cur->bc_mp, level > 0 && bno != NULLAGBLOCK && bno != 0 && bno < agblocks); return 0; } /* * Check that block ptr is ok. */ STATIC int /* error (0 or EFSCORRUPTED) */ xfs_btree_check_ptr( struct xfs_btree_cur *cur, /* btree cursor */ union xfs_btree_ptr *ptr, /* btree block disk address */ int index, /* offset from ptr to check */ int level) /* btree block level */ { if (cur->bc_flags & XFS_BTREE_LONG_PTRS) { return xfs_btree_check_lptr(cur, be64_to_cpu((&ptr->l)[index]), level); } else { return xfs_btree_check_sptr(cur, be32_to_cpu((&ptr->s)[index]), level); } } #endif /* * Calculate CRC on the whole btree block and stuff it into the * long-form btree header. * * Prior to calculting the CRC, pull the LSN out of the buffer log item and put * it into the buffer so recovery knows what the last modifcation was that made * it to disk. */ void xfs_btree_lblock_calc_crc( struct xfs_buf *bp) { struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); struct xfs_buf_log_item *bip = bp->b_fspriv; if (!xfs_sb_version_hascrc(&bp->b_target->bt_mount->m_sb)) return; if (bip) block->bb_u.l.bb_lsn = cpu_to_be64(bip->bli_item.li_lsn); xfs_buf_update_cksum(bp, XFS_BTREE_LBLOCK_CRC_OFF); } bool xfs_btree_lblock_verify_crc( struct xfs_buf *bp) { if (xfs_sb_version_hascrc(&bp->b_target->bt_mount->m_sb)) return xfs_buf_verify_cksum(bp, XFS_BTREE_LBLOCK_CRC_OFF); return true; } /* * Calculate CRC on the whole btree block and stuff it into the * short-form btree header. * * Prior to calculting the CRC, pull the LSN out of the buffer log item and put * it into the buffer so recovery knows what the last modifcation was that made * it to disk. */ void xfs_btree_sblock_calc_crc( struct xfs_buf *bp) { struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); struct xfs_buf_log_item *bip = bp->b_fspriv; if (!xfs_sb_version_hascrc(&bp->b_target->bt_mount->m_sb)) return; if (bip) block->bb_u.s.bb_lsn = cpu_to_be64(bip->bli_item.li_lsn); xfs_buf_update_cksum(bp, XFS_BTREE_SBLOCK_CRC_OFF); } bool xfs_btree_sblock_verify_crc( struct xfs_buf *bp) { if (xfs_sb_version_hascrc(&bp->b_target->bt_mount->m_sb)) return xfs_buf_verify_cksum(bp, XFS_BTREE_SBLOCK_CRC_OFF); return true; } /* * Delete the btree cursor. */ void xfs_btree_del_cursor( xfs_btree_cur_t *cur, /* btree cursor */ int error) /* del because of error */ { int i; /* btree level */ /* * Clear the buffer pointers, and release the buffers. * If we're doing this in the face of an error, we * need to make sure to inspect all of the entries * in the bc_bufs array for buffers to be unlocked. * This is because some of the btree code works from * level n down to 0, and if we get an error along * the way we won't have initialized all the entries * down to 0. */ for (i = 0; i < cur->bc_nlevels; i++) { if (cur->bc_bufs[i]) xfs_trans_brelse(cur->bc_tp, cur->bc_bufs[i]); else if (!error) break; } /* * Can't free a bmap cursor without having dealt with the * allocated indirect blocks' accounting. */ ASSERT(cur->bc_btnum != XFS_BTNUM_BMAP || cur->bc_private.b.allocated == 0); /* * Free the cursor. */ kmem_zone_free(xfs_btree_cur_zone, cur); } /* * Duplicate the btree cursor. * Allocate a new one, copy the record, re-get the buffers. */ int /* error */ xfs_btree_dup_cursor( xfs_btree_cur_t *cur, /* input cursor */ xfs_btree_cur_t **ncur) /* output cursor */ { xfs_buf_t *bp; /* btree block's buffer pointer */ int error; /* error return value */ int i; /* level number of btree block */ xfs_mount_t *mp; /* mount structure for filesystem */ xfs_btree_cur_t *new; /* new cursor value */ xfs_trans_t *tp; /* transaction pointer, can be NULL */ tp = cur->bc_tp; mp = cur->bc_mp; /* * Allocate a new cursor like the old one. */ new = cur->bc_ops->dup_cursor(cur); /* * Copy the record currently in the cursor. */ new->bc_rec = cur->bc_rec; /* * For each level current, re-get the buffer and copy the ptr value. */ for (i = 0; i < new->bc_nlevels; i++) { new->bc_ptrs[i] = cur->bc_ptrs[i]; new->bc_ra[i] = cur->bc_ra[i]; bp = cur->bc_bufs[i]; if (bp) { error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, XFS_BUF_ADDR(bp), mp->m_bsize, 0, &bp, cur->bc_ops->buf_ops); if (error) { xfs_btree_del_cursor(new, error); *ncur = NULL; return error; } } new->bc_bufs[i] = bp; } *ncur = new; return 0; } /* * XFS btree block layout and addressing: * * There are two types of blocks in the btree: leaf and non-leaf blocks. * * The leaf record start with a header then followed by records containing * the values. A non-leaf block also starts with the same header, and * then first contains lookup keys followed by an equal number of pointers * to the btree blocks at the previous level. * * +--------+-------+-------+-------+-------+-------+-------+ * Leaf: | header | rec 1 | rec 2 | rec 3 | rec 4 | rec 5 | rec N | * +--------+-------+-------+-------+-------+-------+-------+ * * +--------+-------+-------+-------+-------+-------+-------+ * Non-Leaf: | header | key 1 | key 2 | key N | ptr 1 | ptr 2 | ptr N | * +--------+-------+-------+-------+-------+-------+-------+ * * The header is called struct xfs_btree_block for reasons better left unknown * and comes in different versions for short (32bit) and long (64bit) block * pointers. The record and key structures are defined by the btree instances * and opaque to the btree core. The block pointers are simple disk endian * integers, available in a short (32bit) and long (64bit) variant. * * The helpers below calculate the offset of a given record, key or pointer * into a btree block (xfs_btree_*_offset) or return a pointer to the given * record, key or pointer (xfs_btree_*_addr). Note that all addressing * inside the btree block is done using indices starting at one, not zero! */ /* * Return size of the btree block header for this btree instance. */ static inline size_t xfs_btree_block_len(struct xfs_btree_cur *cur) { if (cur->bc_flags & XFS_BTREE_LONG_PTRS) { if (cur->bc_flags & XFS_BTREE_CRC_BLOCKS) return XFS_BTREE_LBLOCK_CRC_LEN; return XFS_BTREE_LBLOCK_LEN; } if (cur->bc_flags & XFS_BTREE_CRC_BLOCKS) return XFS_BTREE_SBLOCK_CRC_LEN; return XFS_BTREE_SBLOCK_LEN; } /* * Return size of btree block pointers for this btree instance. */ static inline size_t xfs_btree_ptr_len(struct xfs_btree_cur *cur) { return (cur->bc_flags & XFS_BTREE_LONG_PTRS) ? sizeof(__be64) : sizeof(__be32); } /* * Calculate offset of the n-th record in a btree block. */ STATIC size_t xfs_btree_rec_offset( struct xfs_btree_cur *cur, int n) { return xfs_btree_block_len(cur) + (n - 1) * cur->bc_ops->rec_len; } /* * Calculate offset of the n-th key in a btree block. */ STATIC size_t xfs_btree_key_offset( struct xfs_btree_cur *cur, int n) { return xfs_btree_block_len(cur) + (n - 1) * cur->bc_ops->key_len; } /* * Calculate offset of the n-th block pointer in a btree block. */ STATIC size_t xfs_btree_ptr_offset( struct xfs_btree_cur *cur, int n, int level) { return xfs_btree_block_len(cur) + cur->bc_ops->get_maxrecs(cur, level) * cur->bc_ops->key_len + (n - 1) * xfs_btree_ptr_len(cur); } /* * Return a pointer to the n-th record in the btree block. */ STATIC union xfs_btree_rec * xfs_btree_rec_addr( struct xfs_btree_cur *cur, int n, struct xfs_btree_block *block) { return (union xfs_btree_rec *) ((char *)block + xfs_btree_rec_offset(cur, n)); } /* * Return a pointer to the n-th key in the btree block. */ STATIC union xfs_btree_key * xfs_btree_key_addr( struct xfs_btree_cur *cur, int n, struct xfs_btree_block *block) { return (union xfs_btree_key *) ((char *)block + xfs_btree_key_offset(cur, n)); } /* * Return a pointer to the n-th block pointer in the btree block. */ STATIC union xfs_btree_ptr * xfs_btree_ptr_addr( struct xfs_btree_cur *cur, int n, struct xfs_btree_block *block) { int level = xfs_btree_get_level(block); ASSERT(block->bb_level != 0); return (union xfs_btree_ptr *) ((char *)block + xfs_btree_ptr_offset(cur, n, level)); } /* * Get the root block which is stored in the inode. * * For now this btree implementation assumes the btree root is always * stored in the if_broot field of an inode fork. */ STATIC struct xfs_btree_block * xfs_btree_get_iroot( struct xfs_btree_cur *cur) { struct xfs_ifork *ifp; ifp = XFS_IFORK_PTR(cur->bc_private.b.ip, cur->bc_private.b.whichfork); return (struct xfs_btree_block *)ifp->if_broot; } /* * Retrieve the block pointer from the cursor at the given level. * This may be an inode btree root or from a buffer. */ STATIC struct xfs_btree_block * /* generic btree block pointer */ xfs_btree_get_block( struct xfs_btree_cur *cur, /* btree cursor */ int level, /* level in btree */ struct xfs_buf **bpp) /* buffer containing the block */ { if ((cur->bc_flags & XFS_BTREE_ROOT_IN_INODE) && (level == cur->bc_nlevels - 1)) { *bpp = NULL; return xfs_btree_get_iroot(cur); } *bpp = cur->bc_bufs[level]; return XFS_BUF_TO_BLOCK(*bpp); } /* * Get a buffer for the block, return it with no data read. * Long-form addressing. */ xfs_buf_t * /* buffer for fsbno */ xfs_btree_get_bufl( xfs_mount_t *mp, /* file system mount point */ xfs_trans_t *tp, /* transaction pointer */ xfs_fsblock_t fsbno, /* file system block number */ uint lock) /* lock flags for get_buf */ { xfs_daddr_t d; /* real disk block address */ ASSERT(fsbno != NULLFSBLOCK); d = XFS_FSB_TO_DADDR(mp, fsbno); return xfs_trans_get_buf(tp, mp->m_ddev_targp, d, mp->m_bsize, lock); } /* * Get a buffer for the block, return it with no data read. * Short-form addressing. */ xfs_buf_t * /* buffer for agno/agbno */ xfs_btree_get_bufs( xfs_mount_t *mp, /* file system mount point */ xfs_trans_t *tp, /* transaction pointer */ xfs_agnumber_t agno, /* allocation group number */ xfs_agblock_t agbno, /* allocation group block number */ uint lock) /* lock flags for get_buf */ { xfs_daddr_t d; /* real disk block address */ ASSERT(agno != NULLAGNUMBER); ASSERT(agbno != NULLAGBLOCK); d = XFS_AGB_TO_DADDR(mp, agno, agbno); return xfs_trans_get_buf(tp, mp->m_ddev_targp, d, mp->m_bsize, lock); } /* * Check for the cursor referring to the last block at the given level. */ int /* 1=is last block, 0=not last block */ xfs_btree_islastblock( xfs_btree_cur_t *cur, /* btree cursor */ int level) /* level to check */ { struct xfs_btree_block *block; /* generic btree block pointer */ xfs_buf_t *bp; /* buffer containing block */ block = xfs_btree_get_block(cur, level, &bp); xfs_btree_check_block(cur, block, level, bp); if (cur->bc_flags & XFS_BTREE_LONG_PTRS) return block->bb_u.l.bb_rightsib == cpu_to_be64(NULLFSBLOCK); else return block->bb_u.s.bb_rightsib == cpu_to_be32(NULLAGBLOCK); } /* * Change the cursor to point to the first record at the given level. * Other levels are unaffected. */ STATIC int /* success=1, failure=0 */ xfs_btree_firstrec( xfs_btree_cur_t *cur, /* btree cursor */ int level) /* level to change */ { struct xfs_btree_block *block; /* generic btree block pointer */ xfs_buf_t *bp; /* buffer containing block */ /* * Get the block pointer for this level. */ block = xfs_btree_get_block(cur, level, &bp); xfs_btree_check_block(cur, block, level, bp); /* * It's empty, there is no such record. */ if (!block->bb_numrecs) return 0; /* * Set the ptr value to 1, that's the first record/key. */ cur->bc_ptrs[level] = 1; return 1; } /* * Change the cursor to point to the last record in the current block * at the given level. Other levels are unaffected. */ STATIC int /* success=1, failure=0 */ xfs_btree_lastrec( xfs_btree_cur_t *cur, /* btree cursor */ int level) /* level to change */ { struct xfs_btree_block *block; /* generic btree block pointer */ xfs_buf_t *bp; /* buffer containing block */ /* * Get the block pointer for this level. */ block = xfs_btree_get_block(cur, level, &bp); xfs_btree_check_block(cur, block, level, bp); /* * It's empty, there is no such record. */ if (!block->bb_numrecs) return 0; /* * Set the ptr value to numrecs, that's the last record/key. */ cur->bc_ptrs[level] = be16_to_cpu(block->bb_numrecs); return 1; } /* * Compute first and last byte offsets for the fields given. * Interprets the offsets table, which contains struct field offsets. */ void xfs_btree_offsets( __int64_t fields, /* bitmask of fields */ const short *offsets, /* table of field offsets */ int nbits, /* number of bits to inspect */ int *first, /* output: first byte offset */ int *last) /* output: last byte offset */ { int i; /* current bit number */ __int64_t imask; /* mask for current bit number */ ASSERT(fields != 0); /* * Find the lowest bit, so the first byte offset. */ for (i = 0, imask = 1LL; ; i++, imask <<= 1) { if (imask & fields) { *first = offsets[i]; break; } } /* * Find the highest bit, so the last byte offset. */ for (i = nbits - 1, imask = 1LL << i; ; i--, imask >>= 1) { if (imask & fields) { *last = offsets[i + 1] - 1; break; } } } /* * Get a buffer for the block, return it read in. * Long-form addressing. */ int xfs_btree_read_bufl( struct xfs_mount *mp, /* file system mount point */ struct xfs_trans *tp, /* transaction pointer */ xfs_fsblock_t fsbno, /* file system block number */ uint lock, /* lock flags for read_buf */ struct xfs_buf **bpp, /* buffer for fsbno */ int refval, /* ref count value for buffer */ const struct xfs_buf_ops *ops) { struct xfs_buf *bp; /* return value */ xfs_daddr_t d; /* real disk block address */ int error; ASSERT(fsbno != NULLFSBLOCK); d = XFS_FSB_TO_DADDR(mp, fsbno); error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, d, mp->m_bsize, lock, &bp, ops); if (error) return error; if (bp) xfs_buf_set_ref(bp, refval); *bpp = bp; return 0; } /* * Read-ahead the block, don't wait for it, don't return a buffer. * Long-form addressing. */ /* ARGSUSED */ void xfs_btree_reada_bufl( struct xfs_mount *mp, /* file system mount point */ xfs_fsblock_t fsbno, /* file system block number */ xfs_extlen_t count, /* count of filesystem blocks */ const struct xfs_buf_ops *ops) { xfs_daddr_t d; ASSERT(fsbno != NULLFSBLOCK); d = XFS_FSB_TO_DADDR(mp, fsbno); xfs_buf_readahead(mp->m_ddev_targp, d, mp->m_bsize * count, ops); } /* * Read-ahead the block, don't wait for it, don't return a buffer. * Short-form addressing. */ /* ARGSUSED */ void xfs_btree_reada_bufs( struct xfs_mount *mp, /* file system mount point */ xfs_agnumber_t agno, /* allocation group number */ xfs_agblock_t agbno, /* allocation group block number */ xfs_extlen_t count, /* count of filesystem blocks */ const struct xfs_buf_ops *ops) { xfs_daddr_t d; ASSERT(agno != NULLAGNUMBER); ASSERT(agbno != NULLAGBLOCK); d = XFS_AGB_TO_DADDR(mp, agno, agbno); xfs_buf_readahead(mp->m_ddev_targp, d, mp->m_bsize * count, ops); } STATIC int xfs_btree_readahead_lblock( struct xfs_btree_cur *cur, int lr, struct xfs_btree_block *block) { int rval = 0; xfs_fsblock_t left = be64_to_cpu(block->bb_u.l.bb_leftsib); xfs_fsblock_t right = be64_to_cpu(block->bb_u.l.bb_rightsib); if ((lr & XFS_BTCUR_LEFTRA) && left != NULLFSBLOCK) { xfs_btree_reada_bufl(cur->bc_mp, left, 1, cur->bc_ops->buf_ops); rval++; } if ((lr & XFS_BTCUR_RIGHTRA) && right != NULLFSBLOCK) { xfs_btree_reada_bufl(cur->bc_mp, right, 1, cur->bc_ops->buf_ops); rval++; } return rval; } STATIC int xfs_btree_readahead_sblock( struct xfs_btree_cur *cur, int lr, struct xfs_btree_block *block) { int rval = 0; xfs_agblock_t left = be32_to_cpu(block->bb_u.s.bb_leftsib); xfs_agblock_t right = be32_to_cpu(block->bb_u.s.bb_rightsib); if ((lr & XFS_BTCUR_LEFTRA) && left != NULLAGBLOCK) { xfs_btree_reada_bufs(cur->bc_mp, cur->bc_private.a.agno, left, 1, cur->bc_ops->buf_ops); rval++; } if ((lr & XFS_BTCUR_RIGHTRA) && right != NULLAGBLOCK) { xfs_btree_reada_bufs(cur->bc_mp, cur->bc_private.a.agno, right, 1, cur->bc_ops->buf_ops); rval++; } return rval; } /* * Read-ahead btree blocks, at the given level. * Bits in lr are set from XFS_BTCUR_{LEFT,RIGHT}RA. */ STATIC int xfs_btree_readahead( struct xfs_btree_cur *cur, /* btree cursor */ int lev, /* level in btree */ int lr) /* left/right bits */ { struct xfs_btree_block *block; /* * No readahead needed if we are at the root level and the * btree root is stored in the inode. */ if ((cur->bc_flags & XFS_BTREE_ROOT_IN_INODE) && (lev == cur->bc_nlevels - 1)) return 0; if ((cur->bc_ra[lev] | lr) == cur->bc_ra[lev]) return 0; cur->bc_ra[lev] |= lr; block = XFS_BUF_TO_BLOCK(cur->bc_bufs[lev]); if (cur->bc_flags & XFS_BTREE_LONG_PTRS) return xfs_btree_readahead_lblock(cur, lr, block); return xfs_btree_readahead_sblock(cur, lr, block); } STATIC xfs_daddr_t xfs_btree_ptr_to_daddr( struct xfs_btree_cur *cur, union xfs_btree_ptr *ptr) { if (cur->bc_flags & XFS_BTREE_LONG_PTRS) { ASSERT(ptr->l != cpu_to_be64(NULLFSBLOCK)); return XFS_FSB_TO_DADDR(cur->bc_mp, be64_to_cpu(ptr->l)); } else { ASSERT(cur->bc_private.a.agno != NULLAGNUMBER); ASSERT(ptr->s != cpu_to_be32(NULLAGBLOCK)); return XFS_AGB_TO_DADDR(cur->bc_mp, cur->bc_private.a.agno, be32_to_cpu(ptr->s)); } } /* * Readahead @count btree blocks at the given @ptr location. * * We don't need to care about long or short form btrees here as we have a * method of converting the ptr directly to a daddr available to us. */ STATIC void xfs_btree_readahead_ptr( struct xfs_btree_cur *cur, union xfs_btree_ptr *ptr, xfs_extlen_t count) { xfs_buf_readahead(cur->bc_mp->m_ddev_targp, xfs_btree_ptr_to_daddr(cur, ptr), cur->bc_mp->m_bsize * count, cur->bc_ops->buf_ops); } /* * Set the buffer for level "lev" in the cursor to bp, releasing * any previous buffer. */ STATIC void xfs_btree_setbuf( xfs_btree_cur_t *cur, /* btree cursor */ int lev, /* level in btree */ xfs_buf_t *bp) /* new buffer to set */ { struct xfs_btree_block *b; /* btree block */ if (cur->bc_bufs[lev]) xfs_trans_brelse(cur->bc_tp, cur->bc_bufs[lev]); cur->bc_bufs[lev] = bp; cur->bc_ra[lev] = 0; b = XFS_BUF_TO_BLOCK(bp); if (cur->bc_flags & XFS_BTREE_LONG_PTRS) { if (b->bb_u.l.bb_leftsib == cpu_to_be64(NULLFSBLOCK)) cur->bc_ra[lev] |= XFS_BTCUR_LEFTRA; if (b->bb_u.l.bb_rightsib == cpu_to_be64(NULLFSBLOCK)) cur->bc_ra[lev] |= XFS_BTCUR_RIGHTRA; } else { if (b->bb_u.s.bb_leftsib == cpu_to_be32(NULLAGBLOCK)) cur->bc_ra[lev] |= XFS_BTCUR_LEFTRA; if (b->bb_u.s.bb_rightsib == cpu_to_be32(NULLAGBLOCK)) cur->bc_ra[lev] |= XFS_BTCUR_RIGHTRA; } } STATIC int xfs_btree_ptr_is_null( struct xfs_btree_cur *cur, union xfs_btree_ptr *ptr) { if (cur->bc_flags & XFS_BTREE_LONG_PTRS) return ptr->l == cpu_to_be64(NULLFSBLOCK); else return ptr->s == cpu_to_be32(NULLAGBLOCK); } STATIC void xfs_btree_set_ptr_null( struct xfs_btree_cur *cur, union xfs_btree_ptr *ptr) { if (cur->bc_flags & XFS_BTREE_LONG_PTRS) ptr->l = cpu_to_be64(NULLFSBLOCK); else ptr->s = cpu_to_be32(NULLAGBLOCK); } /* * Get/set/init sibling pointers */ STATIC void xfs_btree_get_sibling( struct xfs_btree_cur *cur, struct xfs_btree_block *block, union xfs_btree_ptr *ptr, int lr) { ASSERT(lr == XFS_BB_LEFTSIB || lr == XFS_BB_RIGHTSIB); if (cur->bc_flags & XFS_BTREE_LONG_PTRS) { if (lr == XFS_BB_RIGHTSIB) ptr->l = block->bb_u.l.bb_rightsib; else ptr->l = block->bb_u.l.bb_leftsib; } else { if (lr == XFS_BB_RIGHTSIB) ptr->s = block->bb_u.s.bb_rightsib; else ptr->s = block->bb_u.s.bb_leftsib; } } STATIC void xfs_btree_set_sibling( struct xfs_btree_cur *cur, struct xfs_btree_block *block, union xfs_btree_ptr *ptr, int lr) { ASSERT(lr == XFS_BB_LEFTSIB || lr == XFS_BB_RIGHTSIB); if (cur->bc_flags & XFS_BTREE_LONG_PTRS) { if (lr == XFS_BB_RIGHTSIB) block->bb_u.l.bb_rightsib = ptr->l; else block->bb_u.l.bb_leftsib = ptr->l; } else { if (lr == XFS_BB_RIGHTSIB) block->bb_u.s.bb_rightsib = ptr->s; else block->bb_u.s.bb_leftsib = ptr->s; } } void xfs_btree_init_block_int( struct xfs_mount *mp, struct xfs_btree_block *buf, xfs_daddr_t blkno, __u32 magic, __u16 level, __u16 numrecs, __u64 owner, unsigned int flags) { buf->bb_magic = cpu_to_be32(magic); buf->bb_level = cpu_to_be16(level); buf->bb_numrecs = cpu_to_be16(numrecs); if (flags & XFS_BTREE_LONG_PTRS) { buf->bb_u.l.bb_leftsib = cpu_to_be64(NULLFSBLOCK); buf->bb_u.l.bb_rightsib = cpu_to_be64(NULLFSBLOCK); if (flags & XFS_BTREE_CRC_BLOCKS) { buf->bb_u.l.bb_blkno = cpu_to_be64(blkno); buf->bb_u.l.bb_owner = cpu_to_be64(owner); uuid_copy(&buf->bb_u.l.bb_uuid, &mp->m_sb.sb_meta_uuid); buf->bb_u.l.bb_pad = 0; buf->bb_u.l.bb_lsn = 0; } } else { /* owner is a 32 bit value on short blocks */ __u32 __owner = (__u32)owner; buf->bb_u.s.bb_leftsib = cpu_to_be32(NULLAGBLOCK); buf->bb_u.s.bb_rightsib = cpu_to_be32(NULLAGBLOCK); if (flags & XFS_BTREE_CRC_BLOCKS) { buf->bb_u.s.bb_blkno = cpu_to_be64(blkno); buf->bb_u.s.bb_owner = cpu_to_be32(__owner); uuid_copy(&buf->bb_u.s.bb_uuid, &mp->m_sb.sb_meta_uuid); buf->bb_u.s.bb_lsn = 0; } } } void xfs_btree_init_block( struct xfs_mount *mp, struct xfs_buf *bp, __u32 magic, __u16 level, __u16 numrecs, __u64 owner, unsigned int flags) { xfs_btree_init_block_int(mp, XFS_BUF_TO_BLOCK(bp), bp->b_bn, magic, level, numrecs, owner, flags); } STATIC void xfs_btree_init_block_cur( struct xfs_btree_cur *cur, struct xfs_buf *bp, int level, int numrecs) { __u64 owner; /* * we can pull the owner from the cursor right now as the different * owners align directly with the pointer size of the btree. This may * change in future, but is safe for current users of the generic btree * code. */ if (cur->bc_flags & XFS_BTREE_LONG_PTRS) owner = cur->bc_private.b.ip->i_ino; else owner = cur->bc_private.a.agno; xfs_btree_init_block_int(cur->bc_mp, XFS_BUF_TO_BLOCK(bp), bp->b_bn, xfs_btree_magic(cur), level, numrecs, owner, cur->bc_flags); } /* * Return true if ptr is the last record in the btree and * we need to track updates to this record. The decision * will be further refined in the update_lastrec method. */ STATIC int xfs_btree_is_lastrec( struct xfs_btree_cur *cur, struct xfs_btree_block *block, int level) { union xfs_btree_ptr ptr; if (level > 0) return 0; if (!(cur->bc_flags & XFS_BTREE_LASTREC_UPDATE)) return 0; xfs_btree_get_sibling(cur, block, &ptr, XFS_BB_RIGHTSIB); if (!xfs_btree_ptr_is_null(cur, &ptr)) return 0; return 1; } STATIC void xfs_btree_buf_to_ptr( struct xfs_btree_cur *cur, struct xfs_buf *bp, union xfs_btree_ptr *ptr) { if (cur->bc_flags & XFS_BTREE_LONG_PTRS) ptr->l = cpu_to_be64(XFS_DADDR_TO_FSB(cur->bc_mp, XFS_BUF_ADDR(bp))); else { ptr->s = cpu_to_be32(xfs_daddr_to_agbno(cur->bc_mp, XFS_BUF_ADDR(bp))); } } STATIC void xfs_btree_set_refs( struct xfs_btree_cur *cur, struct xfs_buf *bp) { switch (cur->bc_btnum) { case XFS_BTNUM_BNO: case XFS_BTNUM_CNT: xfs_buf_set_ref(bp, XFS_ALLOC_BTREE_REF); break; case XFS_BTNUM_INO: case XFS_BTNUM_FINO: xfs_buf_set_ref(bp, XFS_INO_BTREE_REF); break; case XFS_BTNUM_BMAP: xfs_buf_set_ref(bp, XFS_BMAP_BTREE_REF); break; default: ASSERT(0); } } STATIC int xfs_btree_get_buf_block( struct xfs_btree_cur *cur, union xfs_btree_ptr *ptr, int flags, struct xfs_btree_block **block, struct xfs_buf **bpp) { struct xfs_mount *mp = cur->bc_mp; xfs_daddr_t d; /* need to sort out how callers deal with failures first */ ASSERT(!(flags & XBF_TRYLOCK)); d = xfs_btree_ptr_to_daddr(cur, ptr); *bpp = xfs_trans_get_buf(cur->bc_tp, mp->m_ddev_targp, d, mp->m_bsize, flags); if (!*bpp) return -ENOMEM; (*bpp)->b_ops = cur->bc_ops->buf_ops; *block = XFS_BUF_TO_BLOCK(*bpp); return 0; } /* * Read in the buffer at the given ptr and return the buffer and * the block pointer within the buffer. */ STATIC int xfs_btree_read_buf_block( struct xfs_btree_cur *cur, union xfs_btree_ptr *ptr, int flags, struct xfs_btree_block **block, struct xfs_buf **bpp) { struct xfs_mount *mp = cur->bc_mp; xfs_daddr_t d; int error; /* need to sort out how callers deal with failures first */ ASSERT(!(flags & XBF_TRYLOCK)); d = xfs_btree_ptr_to_daddr(cur, ptr); error = xfs_trans_read_buf(mp, cur->bc_tp, mp->m_ddev_targp, d, mp->m_bsize, flags, bpp, cur->bc_ops->buf_ops); if (error) return error; xfs_btree_set_refs(cur, *bpp); *block = XFS_BUF_TO_BLOCK(*bpp); return 0; } /* * Copy keys from one btree block to another. */ STATIC void xfs_btree_copy_keys( struct xfs_btree_cur *cur, union xfs_btree_key *dst_key, union xfs_btree_key *src_key, int numkeys) { ASSERT(numkeys >= 0); memcpy(dst_key, src_key, numkeys * cur->bc_ops->key_len); } /* * Copy records from one btree block to another. */ STATIC void xfs_btree_copy_recs( struct xfs_btree_cur *cur, union xfs_btree_rec *dst_rec, union xfs_btree_rec *src_rec, int numrecs) { ASSERT(numrecs >= 0); memcpy(dst_rec, src_rec, numrecs * cur->bc_ops->rec_len); } /* * Copy block pointers from one btree block to another. */ STATIC void xfs_btree_copy_ptrs( struct xfs_btree_cur *cur, union xfs_btree_ptr *dst_ptr, union xfs_btree_ptr *src_ptr, int numptrs) { ASSERT(numptrs >= 0); memcpy(dst_ptr, src_ptr, numptrs * xfs_btree_ptr_len(cur)); } /* * Shift keys one index left/right inside a single btree block. */ STATIC void xfs_btree_shift_keys( struct xfs_btree_cur *cur, union xfs_btree_key *key, int dir, int numkeys) { char *dst_key; ASSERT(numkeys >= 0); ASSERT(dir == 1 || dir == -1); dst_key = (char *)key + (dir * cur->bc_ops->key_len); memmove(dst_key, key, numkeys * cur->bc_ops->key_len); } /* * Shift records one index left/right inside a single btree block. */ STATIC void xfs_btree_shift_recs( struct xfs_btree_cur *cur, union xfs_btree_rec *rec, int dir, int numrecs) { char *dst_rec; ASSERT(numrecs >= 0); ASSERT(dir == 1 || dir == -1); dst_rec = (char *)rec + (dir * cur->bc_ops->rec_len); memmove(dst_rec, rec, numrecs * cur->bc_ops->rec_len); } /* * Shift block pointers one index left/right inside a single btree block. */ STATIC void xfs_btree_shift_ptrs( struct xfs_btree_cur *cur, union xfs_btree_ptr *ptr, int dir, int numptrs) { char *dst_ptr; ASSERT(numptrs >= 0); ASSERT(dir == 1 || dir == -1); dst_ptr = (char *)ptr + (dir * xfs_btree_ptr_len(cur)); memmove(dst_ptr, ptr, numptrs * xfs_btree_ptr_len(cur)); } /* * Log key values from the btree block. */ STATIC void xfs_btree_log_keys( struct xfs_btree_cur *cur, struct xfs_buf *bp, int first, int last) { XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY); XFS_BTREE_TRACE_ARGBII(cur, bp, first, last); if (bp) { xfs_trans_buf_set_type(cur->bc_tp, bp, XFS_BLFT_BTREE_BUF); xfs_trans_log_buf(cur->bc_tp, bp, xfs_btree_key_offset(cur, first), xfs_btree_key_offset(cur, last + 1) - 1); } else { xfs_trans_log_inode(cur->bc_tp, cur->bc_private.b.ip, xfs_ilog_fbroot(cur->bc_private.b.whichfork)); } XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); } /* * Log record values from the btree block. */ void xfs_btree_log_recs( struct xfs_btree_cur *cur, struct xfs_buf *bp, int first, int last) { XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY); XFS_BTREE_TRACE_ARGBII(cur, bp, first, last); xfs_trans_buf_set_type(cur->bc_tp, bp, XFS_BLFT_BTREE_BUF); xfs_trans_log_buf(cur->bc_tp, bp, xfs_btree_rec_offset(cur, first), xfs_btree_rec_offset(cur, last + 1) - 1); XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); } /* * Log block pointer fields from a btree block (nonleaf). */ STATIC void xfs_btree_log_ptrs( struct xfs_btree_cur *cur, /* btree cursor */ struct xfs_buf *bp, /* buffer containing btree block */ int first, /* index of first pointer to log */ int last) /* index of last pointer to log */ { XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY); XFS_BTREE_TRACE_ARGBII(cur, bp, first, last); if (bp) { struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); int level = xfs_btree_get_level(block); xfs_trans_buf_set_type(cur->bc_tp, bp, XFS_BLFT_BTREE_BUF); xfs_trans_log_buf(cur->bc_tp, bp, xfs_btree_ptr_offset(cur, first, level), xfs_btree_ptr_offset(cur, last + 1, level) - 1); } else { xfs_trans_log_inode(cur->bc_tp, cur->bc_private.b.ip, xfs_ilog_fbroot(cur->bc_private.b.whichfork)); } XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); } /* * Log fields from a btree block header. */ void xfs_btree_log_block( struct xfs_btree_cur *cur, /* btree cursor */ struct xfs_buf *bp, /* buffer containing btree block */ int fields) /* mask of fields: XFS_BB_... */ { int first; /* first byte offset logged */ int last; /* last byte offset logged */ static const short soffsets[] = { /* table of offsets (short) */ offsetof(struct xfs_btree_block, bb_magic), offsetof(struct xfs_btree_block, bb_level), offsetof(struct xfs_btree_block, bb_numrecs), offsetof(struct xfs_btree_block, bb_u.s.bb_leftsib), offsetof(struct xfs_btree_block, bb_u.s.bb_rightsib), offsetof(struct xfs_btree_block, bb_u.s.bb_blkno), offsetof(struct xfs_btree_block, bb_u.s.bb_lsn), offsetof(struct xfs_btree_block, bb_u.s.bb_uuid), offsetof(struct xfs_btree_block, bb_u.s.bb_owner), offsetof(struct xfs_btree_block, bb_u.s.bb_crc), XFS_BTREE_SBLOCK_CRC_LEN }; static const short loffsets[] = { /* table of offsets (long) */ offsetof(struct xfs_btree_block, bb_magic), offsetof(struct xfs_btree_block, bb_level), offsetof(struct xfs_btree_block, bb_numrecs), offsetof(struct xfs_btree_block, bb_u.l.bb_leftsib), offsetof(struct xfs_btree_block, bb_u.l.bb_rightsib), offsetof(struct xfs_btree_block, bb_u.l.bb_blkno), offsetof(struct xfs_btree_block, bb_u.l.bb_lsn), offsetof(struct xfs_btree_block, bb_u.l.bb_uuid), offsetof(struct xfs_btree_block, bb_u.l.bb_owner), offsetof(struct xfs_btree_block, bb_u.l.bb_crc), offsetof(struct xfs_btree_block, bb_u.l.bb_pad), XFS_BTREE_LBLOCK_CRC_LEN }; XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY); XFS_BTREE_TRACE_ARGBI(cur, bp, fields); if (bp) { int nbits; if (cur->bc_flags & XFS_BTREE_CRC_BLOCKS) { /* * We don't log the CRC when updating a btree * block but instead recreate it during log * recovery. As the log buffers have checksums * of their own this is safe and avoids logging a crc * update in a lot of places. */ if (fields == XFS_BB_ALL_BITS) fields = XFS_BB_ALL_BITS_CRC; nbits = XFS_BB_NUM_BITS_CRC; } else { nbits = XFS_BB_NUM_BITS; } xfs_btree_offsets(fields, (cur->bc_flags & XFS_BTREE_LONG_PTRS) ? loffsets : soffsets, nbits, &first, &last); xfs_trans_buf_set_type(cur->bc_tp, bp, XFS_BLFT_BTREE_BUF); xfs_trans_log_buf(cur->bc_tp, bp, first, last); } else { xfs_trans_log_inode(cur->bc_tp, cur->bc_private.b.ip, xfs_ilog_fbroot(cur->bc_private.b.whichfork)); } XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); } /* * Increment cursor by one record at the level. * For nonzero levels the leaf-ward information is untouched. */ int /* error */ xfs_btree_increment( struct xfs_btree_cur *cur, int level, int *stat) /* success/failure */ { struct xfs_btree_block *block; union xfs_btree_ptr ptr; struct xfs_buf *bp; int error; /* error return value */ int lev; XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY); XFS_BTREE_TRACE_ARGI(cur, level); ASSERT(level < cur->bc_nlevels); /* Read-ahead to the right at this level. */ xfs_btree_readahead(cur, level, XFS_BTCUR_RIGHTRA); /* Get a pointer to the btree block. */ block = xfs_btree_get_block(cur, level, &bp); #ifdef DEBUG error = xfs_btree_check_block(cur, block, level, bp); if (error) goto error0; #endif /* We're done if we remain in the block after the increment. */ if (++cur->bc_ptrs[level] <= xfs_btree_get_numrecs(block)) goto out1; /* Fail if we just went off the right edge of the tree. */ xfs_btree_get_sibling(cur, block, &ptr, XFS_BB_RIGHTSIB); if (xfs_btree_ptr_is_null(cur, &ptr)) goto out0; XFS_BTREE_STATS_INC(cur, increment); /* * March up the tree incrementing pointers. * Stop when we don't go off the right edge of a block. */ for (lev = level + 1; lev < cur->bc_nlevels; lev++) { block = xfs_btree_get_block(cur, lev, &bp); #ifdef DEBUG error = xfs_btree_check_block(cur, block, lev, bp); if (error) goto error0; #endif if (++cur->bc_ptrs[lev] <= xfs_btree_get_numrecs(block)) break; /* Read-ahead the right block for the next loop. */ xfs_btree_readahead(cur, lev, XFS_BTCUR_RIGHTRA); } /* * If we went off the root then we are either seriously * confused or have the tree root in an inode. */ if (lev == cur->bc_nlevels) { if (cur->bc_flags & XFS_BTREE_ROOT_IN_INODE) goto out0; ASSERT(0); error = -EFSCORRUPTED; goto error0; } ASSERT(lev < cur->bc_nlevels); /* * Now walk back down the tree, fixing up the cursor's buffer * pointers and key numbers. */ for (block = xfs_btree_get_block(cur, lev, &bp); lev > level; ) { union xfs_btree_ptr *ptrp; ptrp = xfs_btree_ptr_addr(cur, cur->bc_ptrs[lev], block); --lev; error = xfs_btree_read_buf_block(cur, ptrp, 0, &block, &bp); if (error) goto error0; xfs_btree_setbuf(cur, lev, bp); cur->bc_ptrs[lev] = 1; } out1: XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); *stat = 1; return 0; out0: XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); *stat = 0; return 0; error0: XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR); return error; } /* * Decrement cursor by one record at the level. * For nonzero levels the leaf-ward information is untouched. */ int /* error */ xfs_btree_decrement( struct xfs_btree_cur *cur, int level, int *stat) /* success/failure */ { struct xfs_btree_block *block; xfs_buf_t *bp; int error; /* error return value */ int lev; union xfs_btree_ptr ptr; XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY); XFS_BTREE_TRACE_ARGI(cur, level); ASSERT(level < cur->bc_nlevels); /* Read-ahead to the left at this level. */ xfs_btree_readahead(cur, level, XFS_BTCUR_LEFTRA); /* We're done if we remain in the block after the decrement. */ if (--cur->bc_ptrs[level] > 0) goto out1; /* Get a pointer to the btree block. */ block = xfs_btree_get_block(cur, level, &bp); #ifdef DEBUG error = xfs_btree_check_block(cur, block, level, bp); if (error) goto error0; #endif /* Fail if we just went off the left edge of the tree. */ xfs_btree_get_sibling(cur, block, &ptr, XFS_BB_LEFTSIB); if (xfs_btree_ptr_is_null(cur, &ptr)) goto out0; XFS_BTREE_STATS_INC(cur, decrement); /* * March up the tree decrementing pointers. * Stop when we don't go off the left edge of a block. */ for (lev = level + 1; lev < cur->bc_nlevels; lev++) { if (--cur->bc_ptrs[lev] > 0) break; /* Read-ahead the left block for the next loop. */ xfs_btree_readahead(cur, lev, XFS_BTCUR_LEFTRA); } /* * If we went off the root then we are seriously confused. * or the root of the tree is in an inode. */ if (lev == cur->bc_nlevels) { if (cur->bc_flags & XFS_BTREE_ROOT_IN_INODE) goto out0; ASSERT(0); error = -EFSCORRUPTED; goto error0; } ASSERT(lev < cur->bc_nlevels); /* * Now walk back down the tree, fixing up the cursor's buffer * pointers and key numbers. */ for (block = xfs_btree_get_block(cur, lev, &bp); lev > level; ) { union xfs_btree_ptr *ptrp; ptrp = xfs_btree_ptr_addr(cur, cur->bc_ptrs[lev], block); --lev; error = xfs_btree_read_buf_block(cur, ptrp, 0, &block, &bp); if (error) goto error0; xfs_btree_setbuf(cur, lev, bp); cur->bc_ptrs[lev] = xfs_btree_get_numrecs(block); } out1: XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); *stat = 1; return 0; out0: XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); *stat = 0; return 0; error0: XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR); return error; } STATIC int xfs_btree_lookup_get_block( struct xfs_btree_cur *cur, /* btree cursor */ int level, /* level in the btree */ union xfs_btree_ptr *pp, /* ptr to btree block */ struct xfs_btree_block **blkp) /* return btree block */ { struct xfs_buf *bp; /* buffer pointer for btree block */ int error = 0; /* special case the root block if in an inode */ if ((cur->bc_flags & XFS_BTREE_ROOT_IN_INODE) && (level == cur->bc_nlevels - 1)) { *blkp = xfs_btree_get_iroot(cur); return 0; } /* * If the old buffer at this level for the disk address we are * looking for re-use it. * * Otherwise throw it away and get a new one. */ bp = cur->bc_bufs[level]; if (bp && XFS_BUF_ADDR(bp) == xfs_btree_ptr_to_daddr(cur, pp)) { *blkp = XFS_BUF_TO_BLOCK(bp); return 0; } error = xfs_btree_read_buf_block(cur, pp, 0, blkp, &bp); if (error) return error; xfs_btree_setbuf(cur, level, bp); return 0; } /* * Get current search key. For level 0 we don't actually have a key * structure so we make one up from the record. For all other levels * we just return the right key. */ STATIC union xfs_btree_key * xfs_lookup_get_search_key( struct xfs_btree_cur *cur, int level, int keyno, struct xfs_btree_block *block, union xfs_btree_key *kp) { if (level == 0) { cur->bc_ops->init_key_from_rec(kp, xfs_btree_rec_addr(cur, keyno, block)); return kp; } return xfs_btree_key_addr(cur, keyno, block); } /* * Lookup the record. The cursor is made to point to it, based on dir. * stat is set to 0 if can't find any such record, 1 for success. */ int /* error */ xfs_btree_lookup( struct xfs_btree_cur *cur, /* btree cursor */ xfs_lookup_t dir, /* <=, ==, or >= */ int *stat) /* success/failure */ { struct xfs_btree_block *block; /* current btree block */ __int64_t diff; /* difference for the current key */ int error; /* error return value */ int keyno; /* current key number */ int level; /* level in the btree */ union xfs_btree_ptr *pp; /* ptr to btree block */ union xfs_btree_ptr ptr; /* ptr to btree block */ XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY); XFS_BTREE_TRACE_ARGI(cur, dir); XFS_BTREE_STATS_INC(cur, lookup); block = NULL; keyno = 0; /* initialise start pointer from cursor */ cur->bc_ops->init_ptr_from_cur(cur, &ptr); pp = &ptr; /* * Iterate over each level in the btree, starting at the root. * For each level above the leaves, find the key we need, based * on the lookup record, then follow the corresponding block * pointer down to the next level. */ for (level = cur->bc_nlevels - 1, diff = 1; level >= 0; level--) { /* Get the block we need to do the lookup on. */ error = xfs_btree_lookup_get_block(cur, level, pp, &block); if (error) goto error0; if (diff == 0) { /* * If we already had a key match at a higher level, we * know we need to use the first entry in this block. */ keyno = 1; } else { /* Otherwise search this block. Do a binary search. */ int high; /* high entry number */ int low; /* low entry number */ /* Set low and high entry numbers, 1-based. */ low = 1; high = xfs_btree_get_numrecs(block); if (!high) { /* Block is empty, must be an empty leaf. */ ASSERT(level == 0 && cur->bc_nlevels == 1); cur->bc_ptrs[0] = dir != XFS_LOOKUP_LE; XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); *stat = 0; return 0; } /* Binary search the block. */ while (low <= high) { union xfs_btree_key key; union xfs_btree_key *kp; XFS_BTREE_STATS_INC(cur, compare); /* keyno is average of low and high. */ keyno = (low + high) >> 1; /* Get current search key */ kp = xfs_lookup_get_search_key(cur, level, keyno, block, &key); /* * Compute difference to get next direction: * - less than, move right * - greater than, move left * - equal, we're done */ diff = cur->bc_ops->key_diff(cur, kp); if (diff < 0) low = keyno + 1; else if (diff > 0) high = keyno - 1; else break; } } /* * If there are more levels, set up for the next level * by getting the block number and filling in the cursor. */ if (level > 0) { /* * If we moved left, need the previous key number, * unless there isn't one. */ if (diff > 0 && --keyno < 1) keyno = 1; pp = xfs_btree_ptr_addr(cur, keyno, block); #ifdef DEBUG error = xfs_btree_check_ptr(cur, pp, 0, level); if (error) goto error0; #endif cur->bc_ptrs[level] = keyno; } } /* Done with the search. See if we need to adjust the results. */ if (dir != XFS_LOOKUP_LE && diff < 0) { keyno++; /* * If ge search and we went off the end of the block, but it's * not the last block, we're in the wrong block. */ xfs_btree_get_sibling(cur, block, &ptr, XFS_BB_RIGHTSIB); if (dir == XFS_LOOKUP_GE && keyno > xfs_btree_get_numrecs(block) && !xfs_btree_ptr_is_null(cur, &ptr)) { int i; cur->bc_ptrs[0] = keyno; error = xfs_btree_increment(cur, 0, &i); if (error) goto error0; XFS_WANT_CORRUPTED_RETURN(cur->bc_mp, i == 1); XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); *stat = 1; return 0; } } else if (dir == XFS_LOOKUP_LE && diff > 0) keyno--; cur->bc_ptrs[0] = keyno; /* Return if we succeeded or not. */ if (keyno == 0 || keyno > xfs_btree_get_numrecs(block)) *stat = 0; else if (dir != XFS_LOOKUP_EQ || diff == 0) *stat = 1; else *stat = 0; XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); return 0; error0: XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR); return error; } /* * Update keys at all levels from here to the root along the cursor's path. */ STATIC int xfs_btree_updkey( struct xfs_btree_cur *cur, union xfs_btree_key *keyp, int level) { struct xfs_btree_block *block; struct xfs_buf *bp; union xfs_btree_key *kp; int ptr; XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY); XFS_BTREE_TRACE_ARGIK(cur, level, keyp); ASSERT(!(cur->bc_flags & XFS_BTREE_ROOT_IN_INODE) || level >= 1); /* * Go up the tree from this level toward the root. * At each level, update the key value to the value input. * Stop when we reach a level where the cursor isn't pointing * at the first entry in the block. */ for (ptr = 1; ptr == 1 && level < cur->bc_nlevels; level++) { #ifdef DEBUG int error; #endif block = xfs_btree_get_block(cur, level, &bp); #ifdef DEBUG error = xfs_btree_check_block(cur, block, level, bp); if (error) { XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR); return error; } #endif ptr = cur->bc_ptrs[level]; kp = xfs_btree_key_addr(cur, ptr, block); xfs_btree_copy_keys(cur, kp, keyp, 1); xfs_btree_log_keys(cur, bp, ptr, ptr); } XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); return 0; } /* * Update the record referred to by cur to the value in the * given record. This either works (return 0) or gets an * EFSCORRUPTED error. */ int xfs_btree_update( struct xfs_btree_cur *cur, union xfs_btree_rec *rec) { struct xfs_btree_block *block; struct xfs_buf *bp; int error; int ptr; union xfs_btree_rec *rp; XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY); XFS_BTREE_TRACE_ARGR(cur, rec); /* Pick up the current block. */ block = xfs_btree_get_block(cur, 0, &bp); #ifdef DEBUG error = xfs_btree_check_block(cur, block, 0, bp); if (error) goto error0; #endif /* Get the address of the rec to be updated. */ ptr = cur->bc_ptrs[0]; rp = xfs_btree_rec_addr(cur, ptr, block); /* Fill in the new contents and log them. */ xfs_btree_copy_recs(cur, rp, rec, 1); xfs_btree_log_recs(cur, bp, ptr, ptr); /* * If we are tracking the last record in the tree and * we are at the far right edge of the tree, update it. */ if (xfs_btree_is_lastrec(cur, block, 0)) { cur->bc_ops->update_lastrec(cur, block, rec, ptr, LASTREC_UPDATE); } /* Updating first rec in leaf. Pass new key value up to our parent. */ if (ptr == 1) { union xfs_btree_key key; cur->bc_ops->init_key_from_rec(&key, rec); error = xfs_btree_updkey(cur, &key, 1); if (error) goto error0; } XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); return 0; error0: XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR); return error; } /* * Move 1 record left from cur/level if possible. * Update cur to reflect the new path. */ STATIC int /* error */ xfs_btree_lshift( struct xfs_btree_cur *cur, int level, int *stat) /* success/failure */ { union xfs_btree_key key; /* btree key */ struct xfs_buf *lbp; /* left buffer pointer */ struct xfs_btree_block *left; /* left btree block */ int lrecs; /* left record count */ struct xfs_buf *rbp; /* right buffer pointer */ struct xfs_btree_block *right; /* right btree block */ int rrecs; /* right record count */ union xfs_btree_ptr lptr; /* left btree pointer */ union xfs_btree_key *rkp = NULL; /* right btree key */ union xfs_btree_ptr *rpp = NULL; /* right address pointer */ union xfs_btree_rec *rrp = NULL; /* right record pointer */ int error; /* error return value */ XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY); XFS_BTREE_TRACE_ARGI(cur, level); if ((cur->bc_flags & XFS_BTREE_ROOT_IN_INODE) && level == cur->bc_nlevels - 1) goto out0; /* Set up variables for this block as "right". */ right = xfs_btree_get_block(cur, level, &rbp); #ifdef DEBUG error = xfs_btree_check_block(cur, right, level, rbp); if (error) goto error0; #endif /* If we've got no left sibling then we can't shift an entry left. */ xfs_btree_get_sibling(cur, right, &lptr, XFS_BB_LEFTSIB); if (xfs_btree_ptr_is_null(cur, &lptr)) goto out0; /* * If the cursor entry is the one that would be moved, don't * do it... it's too complicated. */ if (cur->bc_ptrs[level] <= 1) goto out0; /* Set up the left neighbor as "left". */ error = xfs_btree_read_buf_block(cur, &lptr, 0, &left, &lbp); if (error) goto error0; /* If it's full, it can't take another entry. */ lrecs = xfs_btree_get_numrecs(left); if (lrecs == cur->bc_ops->get_maxrecs(cur, level)) goto out0; rrecs = xfs_btree_get_numrecs(right); /* * We add one entry to the left side and remove one for the right side. * Account for it here, the changes will be updated on disk and logged * later. */ lrecs++; rrecs--; XFS_BTREE_STATS_INC(cur, lshift); XFS_BTREE_STATS_ADD(cur, moves, 1); /* * If non-leaf, copy a key and a ptr to the left block. * Log the changes to the left block. */ if (level > 0) { /* It's a non-leaf. Move keys and pointers. */ union xfs_btree_key *lkp; /* left btree key */ union xfs_btree_ptr *lpp; /* left address pointer */ lkp = xfs_btree_key_addr(cur, lrecs, left); rkp = xfs_btree_key_addr(cur, 1, right); lpp = xfs_btree_ptr_addr(cur, lrecs, left); rpp = xfs_btree_ptr_addr(cur, 1, right); #ifdef DEBUG error = xfs_btree_check_ptr(cur, rpp, 0, level); if (error) goto error0; #endif xfs_btree_copy_keys(cur, lkp, rkp, 1); xfs_btree_copy_ptrs(cur, lpp, rpp, 1); xfs_btree_log_keys(cur, lbp, lrecs, lrecs); xfs_btree_log_ptrs(cur, lbp, lrecs, lrecs); ASSERT(cur->bc_ops->keys_inorder(cur, xfs_btree_key_addr(cur, lrecs - 1, left), lkp)); } else { /* It's a leaf. Move records. */ union xfs_btree_rec *lrp; /* left record pointer */ lrp = xfs_btree_rec_addr(cur, lrecs, left); rrp = xfs_btree_rec_addr(cur, 1, right); xfs_btree_copy_recs(cur, lrp, rrp, 1); xfs_btree_log_recs(cur, lbp, lrecs, lrecs); ASSERT(cur->bc_ops->recs_inorder(cur, xfs_btree_rec_addr(cur, lrecs - 1, left), lrp)); } xfs_btree_set_numrecs(left, lrecs); xfs_btree_log_block(cur, lbp, XFS_BB_NUMRECS); xfs_btree_set_numrecs(right, rrecs); xfs_btree_log_block(cur, rbp, XFS_BB_NUMRECS); /* * Slide the contents of right down one entry. */ XFS_BTREE_STATS_ADD(cur, moves, rrecs - 1); if (level > 0) { /* It's a nonleaf. operate on keys and ptrs */ #ifdef DEBUG int i; /* loop index */ for (i = 0; i < rrecs; i++) { error = xfs_btree_check_ptr(cur, rpp, i + 1, level); if (error) goto error0; } #endif xfs_btree_shift_keys(cur, xfs_btree_key_addr(cur, 2, right), -1, rrecs); xfs_btree_shift_ptrs(cur, xfs_btree_ptr_addr(cur, 2, right), -1, rrecs); xfs_btree_log_keys(cur, rbp, 1, rrecs); xfs_btree_log_ptrs(cur, rbp, 1, rrecs); } else { /* It's a leaf. operate on records */ xfs_btree_shift_recs(cur, xfs_btree_rec_addr(cur, 2, right), -1, rrecs); xfs_btree_log_recs(cur, rbp, 1, rrecs); /* * If it's the first record in the block, we'll need a key * structure to pass up to the next level (updkey). */ cur->bc_ops->init_key_from_rec(&key, xfs_btree_rec_addr(cur, 1, right)); rkp = &key; } /* Update the parent key values of right. */ error = xfs_btree_updkey(cur, rkp, level + 1); if (error) goto error0; /* Slide the cursor value left one. */ cur->bc_ptrs[level]--; XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); *stat = 1; return 0; out0: XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); *stat = 0; return 0; error0: XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR); return error; } /* * Move 1 record right from cur/level if possible. * Update cur to reflect the new path. */ STATIC int /* error */ xfs_btree_rshift( struct xfs_btree_cur *cur, int level, int *stat) /* success/failure */ { union xfs_btree_key key; /* btree key */ struct xfs_buf *lbp; /* left buffer pointer */ struct xfs_btree_block *left; /* left btree block */ struct xfs_buf *rbp; /* right buffer pointer */ struct xfs_btree_block *right; /* right btree block */ struct xfs_btree_cur *tcur; /* temporary btree cursor */ union xfs_btree_ptr rptr; /* right block pointer */ union xfs_btree_key *rkp; /* right btree key */ int rrecs; /* right record count */ int lrecs; /* left record count */ int error; /* error return value */ int i; /* loop counter */ XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY); XFS_BTREE_TRACE_ARGI(cur, level); if ((cur->bc_flags & XFS_BTREE_ROOT_IN_INODE) && (level == cur->bc_nlevels - 1)) goto out0; /* Set up variables for this block as "left". */ left = xfs_btree_get_block(cur, level, &lbp); #ifdef DEBUG error = xfs_btree_check_block(cur, left, level, lbp); if (error) goto error0; #endif /* If we've got no right sibling then we can't shift an entry right. */ xfs_btree_get_sibling(cur, left, &rptr, XFS_BB_RIGHTSIB); if (xfs_btree_ptr_is_null(cur, &rptr)) goto out0; /* * If the cursor entry is the one that would be moved, don't * do it... it's too complicated. */ lrecs = xfs_btree_get_numrecs(left); if (cur->bc_ptrs[level] >= lrecs) goto out0; /* Set up the right neighbor as "right". */ error = xfs_btree_read_buf_block(cur, &rptr, 0, &right, &rbp); if (error) goto error0; /* If it's full, it can't take another entry. */ rrecs = xfs_btree_get_numrecs(right); if (rrecs == cur->bc_ops->get_maxrecs(cur, level)) goto out0; XFS_BTREE_STATS_INC(cur, rshift); XFS_BTREE_STATS_ADD(cur, moves, rrecs); /* * Make a hole at the start of the right neighbor block, then * copy the last left block entry to the hole. */ if (level > 0) { /* It's a nonleaf. make a hole in the keys and ptrs */ union xfs_btree_key *lkp; union xfs_btree_ptr *lpp; union xfs_btree_ptr *rpp; lkp = xfs_btree_key_addr(cur, lrecs, left); lpp = xfs_btree_ptr_addr(cur, lrecs, left); rkp = xfs_btree_key_addr(cur, 1, right); rpp = xfs_btree_ptr_addr(cur, 1, right); #ifdef DEBUG for (i = rrecs - 1; i >= 0; i--) { error = xfs_btree_check_ptr(cur, rpp, i, level); if (error) goto error0; } #endif xfs_btree_shift_keys(cur, rkp, 1, rrecs); xfs_btree_shift_ptrs(cur, rpp, 1, rrecs); #ifdef DEBUG error = xfs_btree_check_ptr(cur, lpp, 0, level); if (error) goto error0; #endif /* Now put the new data in, and log it. */ xfs_btree_copy_keys(cur, rkp, lkp, 1); xfs_btree_copy_ptrs(cur, rpp, lpp, 1); xfs_btree_log_keys(cur, rbp, 1, rrecs + 1); xfs_btree_log_ptrs(cur, rbp, 1, rrecs + 1); ASSERT(cur->bc_ops->keys_inorder(cur, rkp, xfs_btree_key_addr(cur, 2, right))); } else { /* It's a leaf. make a hole in the records */ union xfs_btree_rec *lrp; union xfs_btree_rec *rrp; lrp = xfs_btree_rec_addr(cur, lrecs, left); rrp = xfs_btree_rec_addr(cur, 1, right); xfs_btree_shift_recs(cur, rrp, 1, rrecs); /* Now put the new data in, and log it. */ xfs_btree_copy_recs(cur, rrp, lrp, 1); xfs_btree_log_recs(cur, rbp, 1, rrecs + 1); cur->bc_ops->init_key_from_rec(&key, rrp); rkp = &key; ASSERT(cur->bc_ops->recs_inorder(cur, rrp, xfs_btree_rec_addr(cur, 2, right))); } /* * Decrement and log left's numrecs, bump and log right's numrecs. */ xfs_btree_set_numrecs(left, --lrecs); xfs_btree_log_block(cur, lbp, XFS_BB_NUMRECS); xfs_btree_set_numrecs(right, ++rrecs); xfs_btree_log_block(cur, rbp, XFS_BB_NUMRECS); /* * Using a temporary cursor, update the parent key values of the * block on the right. */ error = xfs_btree_dup_cursor(cur, &tcur); if (error) goto error0; i = xfs_btree_lastrec(tcur, level); XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, i == 1, error0); error = xfs_btree_increment(tcur, level, &i); if (error) goto error1; error = xfs_btree_updkey(tcur, rkp, level + 1); if (error) goto error1; xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR); XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); *stat = 1; return 0; out0: XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); *stat = 0; return 0; error0: XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR); return error; error1: XFS_BTREE_TRACE_CURSOR(tcur, XBT_ERROR); xfs_btree_del_cursor(tcur, XFS_BTREE_ERROR); return error; } /* * Split cur/level block in half. * Return new block number and the key to its first * record (to be inserted into parent). */ STATIC int /* error */ __xfs_btree_split( struct xfs_btree_cur *cur, int level, union xfs_btree_ptr *ptrp, union xfs_btree_key *key, struct xfs_btree_cur **curp, int *stat) /* success/failure */ { union xfs_btree_ptr lptr; /* left sibling block ptr */ struct xfs_buf *lbp; /* left buffer pointer */ struct xfs_btree_block *left; /* left btree block */ union xfs_btree_ptr rptr; /* right sibling block ptr */ struct xfs_buf *rbp; /* right buffer pointer */ struct xfs_btree_block *right; /* right btree block */ union xfs_btree_ptr rrptr; /* right-right sibling ptr */ struct xfs_buf *rrbp; /* right-right buffer pointer */ struct xfs_btree_block *rrblock; /* right-right btree block */ int lrecs; int rrecs; int src_index; int error; /* error return value */ #ifdef DEBUG int i; #endif XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY); XFS_BTREE_TRACE_ARGIPK(cur, level, *ptrp, key); XFS_BTREE_STATS_INC(cur, split); /* Set up left block (current one). */ left = xfs_btree_get_block(cur, level, &lbp); #ifdef DEBUG error = xfs_btree_check_block(cur, left, level, lbp); if (error) goto error0; #endif xfs_btree_buf_to_ptr(cur, lbp, &lptr); /* Allocate the new block. If we can't do it, we're toast. Give up. */ error = cur->bc_ops->alloc_block(cur, &lptr, &rptr, stat); if (error) goto error0; if (*stat == 0) goto out0; XFS_BTREE_STATS_INC(cur, alloc); /* Set up the new block as "right". */ error = xfs_btree_get_buf_block(cur, &rptr, 0, &right, &rbp); if (error) goto error0; /* Fill in the btree header for the new right block. */ xfs_btree_init_block_cur(cur, rbp, xfs_btree_get_level(left), 0); /* * Split the entries between the old and the new block evenly. * Make sure that if there's an odd number of entries now, that * each new block will have the same number of entries. */ lrecs = xfs_btree_get_numrecs(left); rrecs = lrecs / 2; if ((lrecs & 1) && cur->bc_ptrs[level] <= rrecs + 1) rrecs++; src_index = (lrecs - rrecs + 1); XFS_BTREE_STATS_ADD(cur, moves, rrecs); /* * Copy btree block entries from the left block over to the * new block, the right. Update the right block and log the * changes. */ if (level > 0) { /* It's a non-leaf. Move keys and pointers. */ union xfs_btree_key *lkp; /* left btree key */ union xfs_btree_ptr *lpp; /* left address pointer */ union xfs_btree_key *rkp; /* right btree key */ union xfs_btree_ptr *rpp; /* right address pointer */ lkp = xfs_btree_key_addr(cur, src_index, left); lpp = xfs_btree_ptr_addr(cur, src_index, left); rkp = xfs_btree_key_addr(cur, 1, right); rpp = xfs_btree_ptr_addr(cur, 1, right); #ifdef DEBUG for (i = src_index; i < rrecs; i++) { error = xfs_btree_check_ptr(cur, lpp, i, level); if (error) goto error0; } #endif xfs_btree_copy_keys(cur, rkp, lkp, rrecs); xfs_btree_copy_ptrs(cur, rpp, lpp, rrecs); xfs_btree_log_keys(cur, rbp, 1, rrecs); xfs_btree_log_ptrs(cur, rbp, 1, rrecs); /* Grab the keys to the entries moved to the right block */ xfs_btree_copy_keys(cur, key, rkp, 1); } else { /* It's a leaf. Move records. */ union xfs_btree_rec *lrp; /* left record pointer */ union xfs_btree_rec *rrp; /* right record pointer */ lrp = xfs_btree_rec_addr(cur, src_index, left); rrp = xfs_btree_rec_addr(cur, 1, right); xfs_btree_copy_recs(cur, rrp, lrp, rrecs); xfs_btree_log_recs(cur, rbp, 1, rrecs); cur->bc_ops->init_key_from_rec(key, xfs_btree_rec_addr(cur, 1, right)); } /* * Find the left block number by looking in the buffer. * Adjust numrecs, sibling pointers. */ xfs_btree_get_sibling(cur, left, &rrptr, XFS_BB_RIGHTSIB); xfs_btree_set_sibling(cur, right, &rrptr, XFS_BB_RIGHTSIB); xfs_btree_set_sibling(cur, right, &lptr, XFS_BB_LEFTSIB); xfs_btree_set_sibling(cur, left, &rptr, XFS_BB_RIGHTSIB); lrecs -= rrecs; xfs_btree_set_numrecs(left, lrecs); xfs_btree_set_numrecs(right, xfs_btree_get_numrecs(right) + rrecs); xfs_btree_log_block(cur, rbp, XFS_BB_ALL_BITS); xfs_btree_log_block(cur, lbp, XFS_BB_NUMRECS | XFS_BB_RIGHTSIB); /* * If there's a block to the new block's right, make that block * point back to right instead of to left. */ if (!xfs_btree_ptr_is_null(cur, &rrptr)) { error = xfs_btree_read_buf_block(cur, &rrptr, 0, &rrblock, &rrbp); if (error) goto error0; xfs_btree_set_sibling(cur, rrblock, &rptr, XFS_BB_LEFTSIB); xfs_btree_log_block(cur, rrbp, XFS_BB_LEFTSIB); } /* * If the cursor is really in the right block, move it there. * If it's just pointing past the last entry in left, then we'll * insert there, so don't change anything in that case. */ if (cur->bc_ptrs[level] > lrecs + 1) { xfs_btree_setbuf(cur, level, rbp); cur->bc_ptrs[level] -= lrecs; } /* * If there are more levels, we'll need another cursor which refers * the right block, no matter where this cursor was. */ if (level + 1 < cur->bc_nlevels) { error = xfs_btree_dup_cursor(cur, curp); if (error) goto error0; (*curp)->bc_ptrs[level + 1]++; } *ptrp = rptr; XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); *stat = 1; return 0; out0: XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); *stat = 0; return 0; error0: XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR); return error; } #ifdef __KERNEL__ struct xfs_btree_split_args { struct xfs_btree_cur *cur; int level; union xfs_btree_ptr *ptrp; union xfs_btree_key *key; struct xfs_btree_cur **curp; int *stat; /* success/failure */ int result; bool kswapd; /* allocation in kswapd context */ struct completion *done; struct work_struct work; }; /* * Stack switching interfaces for allocation */ static void xfs_btree_split_worker( struct work_struct *work) { struct xfs_btree_split_args *args = container_of(work, struct xfs_btree_split_args, work); unsigned long pflags; unsigned long new_pflags = PF_FSTRANS; /* * we are in a transaction context here, but may also be doing work * in kswapd context, and hence we may need to inherit that state * temporarily to ensure that we don't block waiting for memory reclaim * in any way. */ if (args->kswapd) new_pflags |= PF_MEMALLOC | PF_SWAPWRITE | PF_KSWAPD; current_set_flags_nested(&pflags, new_pflags); args->result = __xfs_btree_split(args->cur, args->level, args->ptrp, args->key, args->curp, args->stat); complete(args->done); current_restore_flags_nested(&pflags, new_pflags); } /* * BMBT split requests often come in with little stack to work on. Push * them off to a worker thread so there is lots of stack to use. For the other * btree types, just call directly to avoid the context switch overhead here. */ STATIC int /* error */ xfs_btree_split( struct xfs_btree_cur *cur, int level, union xfs_btree_ptr *ptrp, union xfs_btree_key *key, struct xfs_btree_cur **curp, int *stat) /* success/failure */ { struct xfs_btree_split_args args; DECLARE_COMPLETION_ONSTACK(done); if (cur->bc_btnum != XFS_BTNUM_BMAP) return __xfs_btree_split(cur, level, ptrp, key, curp, stat); args.cur = cur; args.level = level; args.ptrp = ptrp; args.key = key; args.curp = curp; args.stat = stat; args.done = &done; args.kswapd = current_is_kswapd(); INIT_WORK_ONSTACK(&args.work, xfs_btree_split_worker); queue_work(xfs_alloc_wq, &args.work); wait_for_completion(&done); destroy_work_on_stack(&args.work); return args.result; } #else /* !KERNEL */ #define xfs_btree_split __xfs_btree_split #endif /* * Copy the old inode root contents into a real block and make the * broot point to it. */ int /* error */ xfs_btree_new_iroot( struct xfs_btree_cur *cur, /* btree cursor */ int *logflags, /* logging flags for inode */ int *stat) /* return status - 0 fail */ { struct xfs_buf *cbp; /* buffer for cblock */ struct xfs_btree_block *block; /* btree block */ struct xfs_btree_block *cblock; /* child btree block */ union xfs_btree_key *ckp; /* child key pointer */ union xfs_btree_ptr *cpp; /* child ptr pointer */ union xfs_btree_key *kp; /* pointer to btree key */ union xfs_btree_ptr *pp; /* pointer to block addr */ union xfs_btree_ptr nptr; /* new block addr */ int level; /* btree level */ int error; /* error return code */ #ifdef DEBUG int i; /* loop counter */ #endif XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY); XFS_BTREE_STATS_INC(cur, newroot); ASSERT(cur->bc_flags & XFS_BTREE_ROOT_IN_INODE); level = cur->bc_nlevels - 1; block = xfs_btree_get_iroot(cur); pp = xfs_btree_ptr_addr(cur, 1, block); /* Allocate the new block. If we can't do it, we're toast. Give up. */ error = cur->bc_ops->alloc_block(cur, pp, &nptr, stat); if (error) goto error0; if (*stat == 0) { XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); return 0; } XFS_BTREE_STATS_INC(cur, alloc); /* Copy the root into a real block. */ error = xfs_btree_get_buf_block(cur, &nptr, 0, &cblock, &cbp); if (error) goto error0; /* * we can't just memcpy() the root in for CRC enabled btree blocks. * In that case have to also ensure the blkno remains correct */ memcpy(cblock, block, xfs_btree_block_len(cur)); if (cur->bc_flags & XFS_BTREE_CRC_BLOCKS) { if (cur->bc_flags & XFS_BTREE_LONG_PTRS) cblock->bb_u.l.bb_blkno = cpu_to_be64(cbp->b_bn); else cblock->bb_u.s.bb_blkno = cpu_to_be64(cbp->b_bn); } be16_add_cpu(&block->bb_level, 1); xfs_btree_set_numrecs(block, 1); cur->bc_nlevels++; cur->bc_ptrs[level + 1] = 1; kp = xfs_btree_key_addr(cur, 1, block); ckp = xfs_btree_key_addr(cur, 1, cblock); xfs_btree_copy_keys(cur, ckp, kp, xfs_btree_get_numrecs(cblock)); cpp = xfs_btree_ptr_addr(cur, 1, cblock); #ifdef DEBUG for (i = 0; i < be16_to_cpu(cblock->bb_numrecs); i++) { error = xfs_btree_check_ptr(cur, pp, i, level); if (error) goto error0; } #endif xfs_btree_copy_ptrs(cur, cpp, pp, xfs_btree_get_numrecs(cblock)); #ifdef DEBUG error = xfs_btree_check_ptr(cur, &nptr, 0, level); if (error) goto error0; #endif xfs_btree_copy_ptrs(cur, pp, &nptr, 1); xfs_iroot_realloc(cur->bc_private.b.ip, 1 - xfs_btree_get_numrecs(cblock), cur->bc_private.b.whichfork); xfs_btree_setbuf(cur, level, cbp); /* * Do all this logging at the end so that * the root is at the right level. */ xfs_btree_log_block(cur, cbp, XFS_BB_ALL_BITS); xfs_btree_log_keys(cur, cbp, 1, be16_to_cpu(cblock->bb_numrecs)); xfs_btree_log_ptrs(cur, cbp, 1, be16_to_cpu(cblock->bb_numrecs)); *logflags |= XFS_ILOG_CORE | xfs_ilog_fbroot(cur->bc_private.b.whichfork); *stat = 1; XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); return 0; error0: XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR); return error; } /* * Allocate a new root block, fill it in. */ STATIC int /* error */ xfs_btree_new_root( struct xfs_btree_cur *cur, /* btree cursor */ int *stat) /* success/failure */ { struct xfs_btree_block *block; /* one half of the old root block */ struct xfs_buf *bp; /* buffer containing block */ int error; /* error return value */ struct xfs_buf *lbp; /* left buffer pointer */ struct xfs_btree_block *left; /* left btree block */ struct xfs_buf *nbp; /* new (root) buffer */ struct xfs_btree_block *new; /* new (root) btree block */ int nptr; /* new value for key index, 1 or 2 */ struct xfs_buf *rbp; /* right buffer pointer */ struct xfs_btree_block *right; /* right btree block */ union xfs_btree_ptr rptr; union xfs_btree_ptr lptr; XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY); XFS_BTREE_STATS_INC(cur, newroot); /* initialise our start point from the cursor */ cur->bc_ops->init_ptr_from_cur(cur, &rptr); /* Allocate the new block. If we can't do it, we're toast. Give up. */ error = cur->bc_ops->alloc_block(cur, &rptr, &lptr, stat); if (error) goto error0; if (*stat == 0) goto out0; XFS_BTREE_STATS_INC(cur, alloc); /* Set up the new block. */ error = xfs_btree_get_buf_block(cur, &lptr, 0, &new, &nbp); if (error) goto error0; /* Set the root in the holding structure increasing the level by 1. */ cur->bc_ops->set_root(cur, &lptr, 1); /* * At the previous root level there are now two blocks: the old root, * and the new block generated when it was split. We don't know which * one the cursor is pointing at, so we set up variables "left" and * "right" for each case. */ block = xfs_btree_get_block(cur, cur->bc_nlevels - 1, &bp); #ifdef DEBUG error = xfs_btree_check_block(cur, block, cur->bc_nlevels - 1, bp); if (error) goto error0; #endif xfs_btree_get_sibling(cur, block, &rptr, XFS_BB_RIGHTSIB); if (!xfs_btree_ptr_is_null(cur, &rptr)) { /* Our block is left, pick up the right block. */ lbp = bp; xfs_btree_buf_to_ptr(cur, lbp, &lptr); left = block; error = xfs_btree_read_buf_block(cur, &rptr, 0, &right, &rbp); if (error) goto error0; bp = rbp; nptr = 1; } else { /* Our block is right, pick up the left block. */ rbp = bp; xfs_btree_buf_to_ptr(cur, rbp, &rptr); right = block; xfs_btree_get_sibling(cur, right, &lptr, XFS_BB_LEFTSIB); error = xfs_btree_read_buf_block(cur, &lptr, 0, &left, &lbp); if (error) goto error0; bp = lbp; nptr = 2; } /* Fill in the new block's btree header and log it. */ xfs_btree_init_block_cur(cur, nbp, cur->bc_nlevels, 2); xfs_btree_log_block(cur, nbp, XFS_BB_ALL_BITS); ASSERT(!xfs_btree_ptr_is_null(cur, &lptr) && !xfs_btree_ptr_is_null(cur, &rptr)); /* Fill in the key data in the new root. */ if (xfs_btree_get_level(left) > 0) { xfs_btree_copy_keys(cur, xfs_btree_key_addr(cur, 1, new), xfs_btree_key_addr(cur, 1, left), 1); xfs_btree_copy_keys(cur, xfs_btree_key_addr(cur, 2, new), xfs_btree_key_addr(cur, 1, right), 1); } else { cur->bc_ops->init_key_from_rec( xfs_btree_key_addr(cur, 1, new), xfs_btree_rec_addr(cur, 1, left)); cur->bc_ops->init_key_from_rec( xfs_btree_key_addr(cur, 2, new), xfs_btree_rec_addr(cur, 1, right)); } xfs_btree_log_keys(cur, nbp, 1, 2); /* Fill in the pointer data in the new root. */ xfs_btree_copy_ptrs(cur, xfs_btree_ptr_addr(cur, 1, new), &lptr, 1); xfs_btree_copy_ptrs(cur, xfs_btree_ptr_addr(cur, 2, new), &rptr, 1); xfs_btree_log_ptrs(cur, nbp, 1, 2); /* Fix up the cursor. */ xfs_btree_setbuf(cur, cur->bc_nlevels, nbp); cur->bc_ptrs[cur->bc_nlevels] = nptr; cur->bc_nlevels++; XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); *stat = 1; return 0; error0: XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR); return error; out0: XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); *stat = 0; return 0; } STATIC int xfs_btree_make_block_unfull( struct xfs_btree_cur *cur, /* btree cursor */ int level, /* btree level */ int numrecs,/* # of recs in block */ int *oindex,/* old tree index */ int *index, /* new tree index */ union xfs_btree_ptr *nptr, /* new btree ptr */ struct xfs_btree_cur **ncur, /* new btree cursor */ union xfs_btree_rec *nrec, /* new record */ int *stat) { union xfs_btree_key key; /* new btree key value */ int error = 0; if ((cur->bc_flags & XFS_BTREE_ROOT_IN_INODE) && level == cur->bc_nlevels - 1) { struct xfs_inode *ip = cur->bc_private.b.ip; if (numrecs < cur->bc_ops->get_dmaxrecs(cur, level)) { /* A root block that can be made bigger. */ xfs_iroot_realloc(ip, 1, cur->bc_private.b.whichfork); } else { /* A root block that needs replacing */ int logflags = 0; error = xfs_btree_new_iroot(cur, &logflags, stat); if (error || *stat == 0) return error; xfs_trans_log_inode(cur->bc_tp, ip, logflags); } return 0; } /* First, try shifting an entry to the right neighbor. */ error = xfs_btree_rshift(cur, level, stat); if (error || *stat) return error; /* Next, try shifting an entry to the left neighbor. */ error = xfs_btree_lshift(cur, level, stat); if (error) return error; if (*stat) { *oindex = *index = cur->bc_ptrs[level]; return 0; } /* * Next, try splitting the current block in half. * * If this works we have to re-set our variables because we * could be in a different block now. */ error = xfs_btree_split(cur, level, nptr, &key, ncur, stat); if (error || *stat == 0) return error; *index = cur->bc_ptrs[level]; cur->bc_ops->init_rec_from_key(&key, nrec); return 0; } /* * Insert one record/level. Return information to the caller * allowing the next level up to proceed if necessary. */ STATIC int xfs_btree_insrec( struct xfs_btree_cur *cur, /* btree cursor */ int level, /* level to insert record at */ union xfs_btree_ptr *ptrp, /* i/o: block number inserted */ union xfs_btree_rec *recp, /* i/o: record data inserted */ struct xfs_btree_cur **curp, /* output: new cursor replacing cur */ int *stat) /* success/failure */ { struct xfs_btree_block *block; /* btree block */ struct xfs_buf *bp; /* buffer for block */ union xfs_btree_key key; /* btree key */ union xfs_btree_ptr nptr; /* new block ptr */ struct xfs_btree_cur *ncur; /* new btree cursor */ union xfs_btree_rec nrec; /* new record count */ int optr; /* old key/record index */ int ptr; /* key/record index */ int numrecs;/* number of records */ int error; /* error return value */ #ifdef DEBUG int i; #endif XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY); XFS_BTREE_TRACE_ARGIPR(cur, level, *ptrp, recp); ncur = NULL; /* * If we have an external root pointer, and we've made it to the * root level, allocate a new root block and we're done. */ if (!(cur->bc_flags & XFS_BTREE_ROOT_IN_INODE) && (level >= cur->bc_nlevels)) { error = xfs_btree_new_root(cur, stat); xfs_btree_set_ptr_null(cur, ptrp); XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); return error; } /* If we're off the left edge, return failure. */ ptr = cur->bc_ptrs[level]; if (ptr == 0) { XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); *stat = 0; return 0; } /* Make a key out of the record data to be inserted, and save it. */ cur->bc_ops->init_key_from_rec(&key, recp); optr = ptr; XFS_BTREE_STATS_INC(cur, insrec); /* Get pointers to the btree buffer and block. */ block = xfs_btree_get_block(cur, level, &bp); numrecs = xfs_btree_get_numrecs(block); #ifdef DEBUG error = xfs_btree_check_block(cur, block, level, bp); if (error) goto error0; /* Check that the new entry is being inserted in the right place. */ if (ptr <= numrecs) { if (level == 0) { ASSERT(cur->bc_ops->recs_inorder(cur, recp, xfs_btree_rec_addr(cur, ptr, block))); } else { ASSERT(cur->bc_ops->keys_inorder(cur, &key, xfs_btree_key_addr(cur, ptr, block))); } } #endif /* * If the block is full, we can't insert the new entry until we * make the block un-full. */ xfs_btree_set_ptr_null(cur, &nptr); if (numrecs == cur->bc_ops->get_maxrecs(cur, level)) { error = xfs_btree_make_block_unfull(cur, level, numrecs, &optr, &ptr, &nptr, &ncur, &nrec, stat); if (error || *stat == 0) goto error0; } /* * The current block may have changed if the block was * previously full and we have just made space in it. */ block = xfs_btree_get_block(cur, level, &bp); numrecs = xfs_btree_get_numrecs(block); #ifdef DEBUG error = xfs_btree_check_block(cur, block, level, bp); if (error) return error; #endif /* * At this point we know there's room for our new entry in the block * we're pointing at. */ XFS_BTREE_STATS_ADD(cur, moves, numrecs - ptr + 1); if (level > 0) { /* It's a nonleaf. make a hole in the keys and ptrs */ union xfs_btree_key *kp; union xfs_btree_ptr *pp; kp = xfs_btree_key_addr(cur, ptr, block); pp = xfs_btree_ptr_addr(cur, ptr, block); #ifdef DEBUG for (i = numrecs - ptr; i >= 0; i--) { error = xfs_btree_check_ptr(cur, pp, i, level); if (error) return error; } #endif xfs_btree_shift_keys(cur, kp, 1, numrecs - ptr + 1); xfs_btree_shift_ptrs(cur, pp, 1, numrecs - ptr + 1); #ifdef DEBUG error = xfs_btree_check_ptr(cur, ptrp, 0, level); if (error) goto error0; #endif /* Now put the new data in, bump numrecs and log it. */ xfs_btree_copy_keys(cur, kp, &key, 1); xfs_btree_copy_ptrs(cur, pp, ptrp, 1); numrecs++; xfs_btree_set_numrecs(block, numrecs); xfs_btree_log_ptrs(cur, bp, ptr, numrecs); xfs_btree_log_keys(cur, bp, ptr, numrecs); #ifdef DEBUG if (ptr < numrecs) { ASSERT(cur->bc_ops->keys_inorder(cur, kp, xfs_btree_key_addr(cur, ptr + 1, block))); } #endif } else { /* It's a leaf. make a hole in the records */ union xfs_btree_rec *rp; rp = xfs_btree_rec_addr(cur, ptr, block); xfs_btree_shift_recs(cur, rp, 1, numrecs - ptr + 1); /* Now put the new data in, bump numrecs and log it. */ xfs_btree_copy_recs(cur, rp, recp, 1); xfs_btree_set_numrecs(block, ++numrecs); xfs_btree_log_recs(cur, bp, ptr, numrecs); #ifdef DEBUG if (ptr < numrecs) { ASSERT(cur->bc_ops->recs_inorder(cur, rp, xfs_btree_rec_addr(cur, ptr + 1, block))); } #endif } /* Log the new number of records in the btree header. */ xfs_btree_log_block(cur, bp, XFS_BB_NUMRECS); /* If we inserted at the start of a block, update the parents' keys. */ if (optr == 1) { error = xfs_btree_updkey(cur, &key, level + 1); if (error) goto error0; } /* * If we are tracking the last record in the tree and * we are at the far right edge of the tree, update it. */ if (xfs_btree_is_lastrec(cur, block, level)) { cur->bc_ops->update_lastrec(cur, block, recp, ptr, LASTREC_INSREC); } /* * Return the new block number, if any. * If there is one, give back a record value and a cursor too. */ *ptrp = nptr; if (!xfs_btree_ptr_is_null(cur, &nptr)) { *recp = nrec; *curp = ncur; } XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); *stat = 1; return 0; error0: XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR); return error; } /* * Insert the record at the point referenced by cur. * * A multi-level split of the tree on insert will invalidate the original * cursor. All callers of this function should assume that the cursor is * no longer valid and revalidate it. */ int xfs_btree_insert( struct xfs_btree_cur *cur, int *stat) { int error; /* error return value */ int i; /* result value, 0 for failure */ int level; /* current level number in btree */ union xfs_btree_ptr nptr; /* new block number (split result) */ struct xfs_btree_cur *ncur; /* new cursor (split result) */ struct xfs_btree_cur *pcur; /* previous level's cursor */ union xfs_btree_rec rec; /* record to insert */ level = 0; ncur = NULL; pcur = cur; xfs_btree_set_ptr_null(cur, &nptr); cur->bc_ops->init_rec_from_cur(cur, &rec); /* * Loop going up the tree, starting at the leaf level. * Stop when we don't get a split block, that must mean that * the insert is finished with this level. */ do { /* * Insert nrec/nptr into this level of the tree. * Note if we fail, nptr will be null. */ error = xfs_btree_insrec(pcur, level, &nptr, &rec, &ncur, &i); if (error) { if (pcur != cur) xfs_btree_del_cursor(pcur, XFS_BTREE_ERROR); goto error0; } XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, i == 1, error0); level++; /* * See if the cursor we just used is trash. * Can't trash the caller's cursor, but otherwise we should * if ncur is a new cursor or we're about to be done. */ if (pcur != cur && (ncur || xfs_btree_ptr_is_null(cur, &nptr))) { /* Save the state from the cursor before we trash it */ if (cur->bc_ops->update_cursor) cur->bc_ops->update_cursor(pcur, cur); cur->bc_nlevels = pcur->bc_nlevels; xfs_btree_del_cursor(pcur, XFS_BTREE_NOERROR); } /* If we got a new cursor, switch to it. */ if (ncur) { pcur = ncur; ncur = NULL; } } while (!xfs_btree_ptr_is_null(cur, &nptr)); XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); *stat = i; return 0; error0: XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR); return error; } /* * Try to merge a non-leaf block back into the inode root. * * Note: the killroot names comes from the fact that we're effectively * killing the old root block. But because we can't just delete the * inode we have to copy the single block it was pointing to into the * inode. */ STATIC int xfs_btree_kill_iroot( struct xfs_btree_cur *cur) { int whichfork = cur->bc_private.b.whichfork; struct xfs_inode *ip = cur->bc_private.b.ip; struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, whichfork); struct xfs_btree_block *block; struct xfs_btree_block *cblock; union xfs_btree_key *kp; union xfs_btree_key *ckp; union xfs_btree_ptr *pp; union xfs_btree_ptr *cpp; struct xfs_buf *cbp; int level; int index; int numrecs; #ifdef DEBUG union xfs_btree_ptr ptr; int i; #endif XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY); ASSERT(cur->bc_flags & XFS_BTREE_ROOT_IN_INODE); ASSERT(cur->bc_nlevels > 1); /* * Don't deal with the root block needs to be a leaf case. * We're just going to turn the thing back into extents anyway. */ level = cur->bc_nlevels - 1; if (level == 1) goto out0; /* * Give up if the root has multiple children. */ block = xfs_btree_get_iroot(cur); if (xfs_btree_get_numrecs(block) != 1) goto out0; cblock = xfs_btree_get_block(cur, level - 1, &cbp); numrecs = xfs_btree_get_numrecs(cblock); /* * Only do this if the next level will fit. * Then the data must be copied up to the inode, * instead of freeing the root you free the next level. */ if (numrecs > cur->bc_ops->get_dmaxrecs(cur, level)) goto out0; XFS_BTREE_STATS_INC(cur, killroot); #ifdef DEBUG xfs_btree_get_sibling(cur, block, &ptr, XFS_BB_LEFTSIB); ASSERT(xfs_btree_ptr_is_null(cur, &ptr)); xfs_btree_get_sibling(cur, block, &ptr, XFS_BB_RIGHTSIB); ASSERT(xfs_btree_ptr_is_null(cur, &ptr)); #endif index = numrecs - cur->bc_ops->get_maxrecs(cur, level); if (index) { xfs_iroot_realloc(cur->bc_private.b.ip, index, cur->bc_private.b.whichfork); block = ifp->if_broot; } be16_add_cpu(&block->bb_numrecs, index); ASSERT(block->bb_numrecs == cblock->bb_numrecs); kp = xfs_btree_key_addr(cur, 1, block); ckp = xfs_btree_key_addr(cur, 1, cblock); xfs_btree_copy_keys(cur, kp, ckp, numrecs); pp = xfs_btree_ptr_addr(cur, 1, block); cpp = xfs_btree_ptr_addr(cur, 1, cblock); #ifdef DEBUG for (i = 0; i < numrecs; i++) { int error; error = xfs_btree_check_ptr(cur, cpp, i, level - 1); if (error) { XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR); return error; } } #endif xfs_btree_copy_ptrs(cur, pp, cpp, numrecs); cur->bc_ops->free_block(cur, cbp); XFS_BTREE_STATS_INC(cur, free); cur->bc_bufs[level - 1] = NULL; be16_add_cpu(&block->bb_level, -1); xfs_trans_log_inode(cur->bc_tp, ip, XFS_ILOG_CORE | xfs_ilog_fbroot(cur->bc_private.b.whichfork)); cur->bc_nlevels--; out0: XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); return 0; } /* * Kill the current root node, and replace it with it's only child node. */ STATIC int xfs_btree_kill_root( struct xfs_btree_cur *cur, struct xfs_buf *bp, int level, union xfs_btree_ptr *newroot) { int error; XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY); XFS_BTREE_STATS_INC(cur, killroot); /* * Update the root pointer, decreasing the level by 1 and then * free the old root. */ cur->bc_ops->set_root(cur, newroot, -1); error = cur->bc_ops->free_block(cur, bp); if (error) { XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR); return error; } XFS_BTREE_STATS_INC(cur, free); cur->bc_bufs[level] = NULL; cur->bc_ra[level] = 0; cur->bc_nlevels--; XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); return 0; } STATIC int xfs_btree_dec_cursor( struct xfs_btree_cur *cur, int level, int *stat) { int error; int i; if (level > 0) { error = xfs_btree_decrement(cur, level, &i); if (error) return error; } XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); *stat = 1; return 0; } /* * Single level of the btree record deletion routine. * Delete record pointed to by cur/level. * Remove the record from its block then rebalance the tree. * Return 0 for error, 1 for done, 2 to go on to the next level. */ STATIC int /* error */ xfs_btree_delrec( struct xfs_btree_cur *cur, /* btree cursor */ int level, /* level removing record from */ int *stat) /* fail/done/go-on */ { struct xfs_btree_block *block; /* btree block */ union xfs_btree_ptr cptr; /* current block ptr */ struct xfs_buf *bp; /* buffer for block */ int error; /* error return value */ int i; /* loop counter */ union xfs_btree_key key; /* storage for keyp */ union xfs_btree_key *keyp = &key; /* passed to the next level */ union xfs_btree_ptr lptr; /* left sibling block ptr */ struct xfs_buf *lbp; /* left buffer pointer */ struct xfs_btree_block *left; /* left btree block */ int lrecs = 0; /* left record count */ int ptr; /* key/record index */ union xfs_btree_ptr rptr; /* right sibling block ptr */ struct xfs_buf *rbp; /* right buffer pointer */ struct xfs_btree_block *right; /* right btree block */ struct xfs_btree_block *rrblock; /* right-right btree block */ struct xfs_buf *rrbp; /* right-right buffer pointer */ int rrecs = 0; /* right record count */ struct xfs_btree_cur *tcur; /* temporary btree cursor */ int numrecs; /* temporary numrec count */ XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY); XFS_BTREE_TRACE_ARGI(cur, level); tcur = NULL; /* Get the index of the entry being deleted, check for nothing there. */ ptr = cur->bc_ptrs[level]; if (ptr == 0) { XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); *stat = 0; return 0; } /* Get the buffer & block containing the record or key/ptr. */ block = xfs_btree_get_block(cur, level, &bp); numrecs = xfs_btree_get_numrecs(block); #ifdef DEBUG error = xfs_btree_check_block(cur, block, level, bp); if (error) goto error0; #endif /* Fail if we're off the end of the block. */ if (ptr > numrecs) { XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); *stat = 0; return 0; } XFS_BTREE_STATS_INC(cur, delrec); XFS_BTREE_STATS_ADD(cur, moves, numrecs - ptr); /* Excise the entries being deleted. */ if (level > 0) { /* It's a nonleaf. operate on keys and ptrs */ union xfs_btree_key *lkp; union xfs_btree_ptr *lpp; lkp = xfs_btree_key_addr(cur, ptr + 1, block); lpp = xfs_btree_ptr_addr(cur, ptr + 1, block); #ifdef DEBUG for (i = 0; i < numrecs - ptr; i++) { error = xfs_btree_check_ptr(cur, lpp, i, level); if (error) goto error0; } #endif if (ptr < numrecs) { xfs_btree_shift_keys(cur, lkp, -1, numrecs - ptr); xfs_btree_shift_ptrs(cur, lpp, -1, numrecs - ptr); xfs_btree_log_keys(cur, bp, ptr, numrecs - 1); xfs_btree_log_ptrs(cur, bp, ptr, numrecs - 1); } /* * If it's the first record in the block, we'll need to pass a * key up to the next level (updkey). */ if (ptr == 1) keyp = xfs_btree_key_addr(cur, 1, block); } else { /* It's a leaf. operate on records */ if (ptr < numrecs) { xfs_btree_shift_recs(cur, xfs_btree_rec_addr(cur, ptr + 1, block), -1, numrecs - ptr); xfs_btree_log_recs(cur, bp, ptr, numrecs - 1); } /* * If it's the first record in the block, we'll need a key * structure to pass up to the next level (updkey). */ if (ptr == 1) { cur->bc_ops->init_key_from_rec(&key, xfs_btree_rec_addr(cur, 1, block)); keyp = &key; } } /* * Decrement and log the number of entries in the block. */ xfs_btree_set_numrecs(block, --numrecs); xfs_btree_log_block(cur, bp, XFS_BB_NUMRECS); /* * If we are tracking the last record in the tree and * we are at the far right edge of the tree, update it. */ if (xfs_btree_is_lastrec(cur, block, level)) { cur->bc_ops->update_lastrec(cur, block, NULL, ptr, LASTREC_DELREC); } /* * We're at the root level. First, shrink the root block in-memory. * Try to get rid of the next level down. If we can't then there's * nothing left to do. */ if (level == cur->bc_nlevels - 1) { if (cur->bc_flags & XFS_BTREE_ROOT_IN_INODE) { xfs_iroot_realloc(cur->bc_private.b.ip, -1, cur->bc_private.b.whichfork); error = xfs_btree_kill_iroot(cur); if (error) goto error0; error = xfs_btree_dec_cursor(cur, level, stat); if (error) goto error0; *stat = 1; return 0; } /* * If this is the root level, and there's only one entry left, * and it's NOT the leaf level, then we can get rid of this * level. */ if (numrecs == 1 && level > 0) { union xfs_btree_ptr *pp; /* * pp is still set to the first pointer in the block. * Make it the new root of the btree. */ pp = xfs_btree_ptr_addr(cur, 1, block); error = xfs_btree_kill_root(cur, bp, level, pp); if (error) goto error0; } else if (level > 0) { error = xfs_btree_dec_cursor(cur, level, stat); if (error) goto error0; } *stat = 1; return 0; } /* * If we deleted the leftmost entry in the block, update the * key values above us in the tree. */ if (ptr == 1) { error = xfs_btree_updkey(cur, keyp, level + 1); if (error) goto error0; } /* * If the number of records remaining in the block is at least * the minimum, we're done. */ if (numrecs >= cur->bc_ops->get_minrecs(cur, level)) { error = xfs_btree_dec_cursor(cur, level, stat); if (error) goto error0; return 0; } /* * Otherwise, we have to move some records around to keep the * tree balanced. Look at the left and right sibling blocks to * see if we can re-balance by moving only one record. */ xfs_btree_get_sibling(cur, block, &rptr, XFS_BB_RIGHTSIB); xfs_btree_get_sibling(cur, block, &lptr, XFS_BB_LEFTSIB); if (cur->bc_flags & XFS_BTREE_ROOT_IN_INODE) { /* * One child of root, need to get a chance to copy its contents * into the root and delete it. Can't go up to next level, * there's nothing to delete there. */ if (xfs_btree_ptr_is_null(cur, &rptr) && xfs_btree_ptr_is_null(cur, &lptr) && level == cur->bc_nlevels - 2) { error = xfs_btree_kill_iroot(cur); if (!error) error = xfs_btree_dec_cursor(cur, level, stat); if (error) goto error0; return 0; } } ASSERT(!xfs_btree_ptr_is_null(cur, &rptr) || !xfs_btree_ptr_is_null(cur, &lptr)); /* * Duplicate the cursor so our btree manipulations here won't * disrupt the next level up. */ error = xfs_btree_dup_cursor(cur, &tcur); if (error) goto error0; /* * If there's a right sibling, see if it's ok to shift an entry * out of it. */ if (!xfs_btree_ptr_is_null(cur, &rptr)) { /* * Move the temp cursor to the last entry in the next block. * Actually any entry but the first would suffice. */ i = xfs_btree_lastrec(tcur, level); XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, i == 1, error0); error = xfs_btree_increment(tcur, level, &i); if (error) goto error0; XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, i == 1, error0); i = xfs_btree_lastrec(tcur, level); XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, i == 1, error0); /* Grab a pointer to the block. */ right = xfs_btree_get_block(tcur, level, &rbp); #ifdef DEBUG error = xfs_btree_check_block(tcur, right, level, rbp); if (error) goto error0; #endif /* Grab the current block number, for future use. */ xfs_btree_get_sibling(tcur, right, &cptr, XFS_BB_LEFTSIB); /* * If right block is full enough so that removing one entry * won't make it too empty, and left-shifting an entry out * of right to us works, we're done. */ if (xfs_btree_get_numrecs(right) - 1 >= cur->bc_ops->get_minrecs(tcur, level)) { error = xfs_btree_lshift(tcur, level, &i); if (error) goto error0; if (i) { ASSERT(xfs_btree_get_numrecs(block) >= cur->bc_ops->get_minrecs(tcur, level)); xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR); tcur = NULL; error = xfs_btree_dec_cursor(cur, level, stat); if (error) goto error0; return 0; } } /* * Otherwise, grab the number of records in right for * future reference, and fix up the temp cursor to point * to our block again (last record). */ rrecs = xfs_btree_get_numrecs(right); if (!xfs_btree_ptr_is_null(cur, &lptr)) { i = xfs_btree_firstrec(tcur, level); XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, i == 1, error0); error = xfs_btree_decrement(tcur, level, &i); if (error) goto error0; XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, i == 1, error0); } } /* * If there's a left sibling, see if it's ok to shift an entry * out of it. */ if (!xfs_btree_ptr_is_null(cur, &lptr)) { /* * Move the temp cursor to the first entry in the * previous block. */ i = xfs_btree_firstrec(tcur, level); XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, i == 1, error0); error = xfs_btree_decrement(tcur, level, &i); if (error) goto error0; i = xfs_btree_firstrec(tcur, level); XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, i == 1, error0); /* Grab a pointer to the block. */ left = xfs_btree_get_block(tcur, level, &lbp); #ifdef DEBUG error = xfs_btree_check_block(cur, left, level, lbp); if (error) goto error0; #endif /* Grab the current block number, for future use. */ xfs_btree_get_sibling(tcur, left, &cptr, XFS_BB_RIGHTSIB); /* * If left block is full enough so that removing one entry * won't make it too empty, and right-shifting an entry out * of left to us works, we're done. */ if (xfs_btree_get_numrecs(left) - 1 >= cur->bc_ops->get_minrecs(tcur, level)) { error = xfs_btree_rshift(tcur, level, &i); if (error) goto error0; if (i) { ASSERT(xfs_btree_get_numrecs(block) >= cur->bc_ops->get_minrecs(tcur, level)); xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR); tcur = NULL; if (level == 0) cur->bc_ptrs[0]++; XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); *stat = 1; return 0; } } /* * Otherwise, grab the number of records in right for * future reference. */ lrecs = xfs_btree_get_numrecs(left); } /* Delete the temp cursor, we're done with it. */ xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR); tcur = NULL; /* If here, we need to do a join to keep the tree balanced. */ ASSERT(!xfs_btree_ptr_is_null(cur, &cptr)); if (!xfs_btree_ptr_is_null(cur, &lptr) && lrecs + xfs_btree_get_numrecs(block) <= cur->bc_ops->get_maxrecs(cur, level)) { /* * Set "right" to be the starting block, * "left" to be the left neighbor. */ rptr = cptr; right = block; rbp = bp; error = xfs_btree_read_buf_block(cur, &lptr, 0, &left, &lbp); if (error) goto error0; /* * If that won't work, see if we can join with the right neighbor block. */ } else if (!xfs_btree_ptr_is_null(cur, &rptr) && rrecs + xfs_btree_get_numrecs(block) <= cur->bc_ops->get_maxrecs(cur, level)) { /* * Set "left" to be the starting block, * "right" to be the right neighbor. */ lptr = cptr; left = block; lbp = bp; error = xfs_btree_read_buf_block(cur, &rptr, 0, &right, &rbp); if (error) goto error0; /* * Otherwise, we can't fix the imbalance. * Just return. This is probably a logic error, but it's not fatal. */ } else { error = xfs_btree_dec_cursor(cur, level, stat); if (error) goto error0; return 0; } rrecs = xfs_btree_get_numrecs(right); lrecs = xfs_btree_get_numrecs(left); /* * We're now going to join "left" and "right" by moving all the stuff * in "right" to "left" and deleting "right". */ XFS_BTREE_STATS_ADD(cur, moves, rrecs); if (level > 0) { /* It's a non-leaf. Move keys and pointers. */ union xfs_btree_key *lkp; /* left btree key */ union xfs_btree_ptr *lpp; /* left address pointer */ union xfs_btree_key *rkp; /* right btree key */ union xfs_btree_ptr *rpp; /* right address pointer */ lkp = xfs_btree_key_addr(cur, lrecs + 1, left); lpp = xfs_btree_ptr_addr(cur, lrecs + 1, left); rkp = xfs_btree_key_addr(cur, 1, right); rpp = xfs_btree_ptr_addr(cur, 1, right); #ifdef DEBUG for (i = 1; i < rrecs; i++) { error = xfs_btree_check_ptr(cur, rpp, i, level); if (error) goto error0; } #endif xfs_btree_copy_keys(cur, lkp, rkp, rrecs); xfs_btree_copy_ptrs(cur, lpp, rpp, rrecs); xfs_btree_log_keys(cur, lbp, lrecs + 1, lrecs + rrecs); xfs_btree_log_ptrs(cur, lbp, lrecs + 1, lrecs + rrecs); } else { /* It's a leaf. Move records. */ union xfs_btree_rec *lrp; /* left record pointer */ union xfs_btree_rec *rrp; /* right record pointer */ lrp = xfs_btree_rec_addr(cur, lrecs + 1, left); rrp = xfs_btree_rec_addr(cur, 1, right); xfs_btree_copy_recs(cur, lrp, rrp, rrecs); xfs_btree_log_recs(cur, lbp, lrecs + 1, lrecs + rrecs); } XFS_BTREE_STATS_INC(cur, join); /* * Fix up the number of records and right block pointer in the * surviving block, and log it. */ xfs_btree_set_numrecs(left, lrecs + rrecs); xfs_btree_get_sibling(cur, right, &cptr, XFS_BB_RIGHTSIB), xfs_btree_set_sibling(cur, left, &cptr, XFS_BB_RIGHTSIB); xfs_btree_log_block(cur, lbp, XFS_BB_NUMRECS | XFS_BB_RIGHTSIB); /* If there is a right sibling, point it to the remaining block. */ xfs_btree_get_sibling(cur, left, &cptr, XFS_BB_RIGHTSIB); if (!xfs_btree_ptr_is_null(cur, &cptr)) { error = xfs_btree_read_buf_block(cur, &cptr, 0, &rrblock, &rrbp); if (error) goto error0; xfs_btree_set_sibling(cur, rrblock, &lptr, XFS_BB_LEFTSIB); xfs_btree_log_block(cur, rrbp, XFS_BB_LEFTSIB); } /* Free the deleted block. */ error = cur->bc_ops->free_block(cur, rbp); if (error) goto error0; XFS_BTREE_STATS_INC(cur, free); /* * If we joined with the left neighbor, set the buffer in the * cursor to the left block, and fix up the index. */ if (bp != lbp) { cur->bc_bufs[level] = lbp; cur->bc_ptrs[level] += lrecs; cur->bc_ra[level] = 0; } /* * If we joined with the right neighbor and there's a level above * us, increment the cursor at that level. */ else if ((cur->bc_flags & XFS_BTREE_ROOT_IN_INODE) || (level + 1 < cur->bc_nlevels)) { error = xfs_btree_increment(cur, level + 1, &i); if (error) goto error0; } /* * Readjust the ptr at this level if it's not a leaf, since it's * still pointing at the deletion point, which makes the cursor * inconsistent. If this makes the ptr 0, the caller fixes it up. * We can't use decrement because it would change the next level up. */ if (level > 0) cur->bc_ptrs[level]--; XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); /* Return value means the next level up has something to do. */ *stat = 2; return 0; error0: XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR); if (tcur) xfs_btree_del_cursor(tcur, XFS_BTREE_ERROR); return error; } /* * Delete the record pointed to by cur. * The cursor refers to the place where the record was (could be inserted) * when the operation returns. */ int /* error */ xfs_btree_delete( struct xfs_btree_cur *cur, int *stat) /* success/failure */ { int error; /* error return value */ int level; int i; XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY); /* * Go up the tree, starting at leaf level. * * If 2 is returned then a join was done; go to the next level. * Otherwise we are done. */ for (level = 0, i = 2; i == 2; level++) { error = xfs_btree_delrec(cur, level, &i); if (error) goto error0; } if (i == 0) { for (level = 1; level < cur->bc_nlevels; level++) { if (cur->bc_ptrs[level] == 0) { error = xfs_btree_decrement(cur, level, &i); if (error) goto error0; break; } } } XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); *stat = i; return 0; error0: XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR); return error; } /* * Get the data from the pointed-to record. */ int /* error */ xfs_btree_get_rec( struct xfs_btree_cur *cur, /* btree cursor */ union xfs_btree_rec **recp, /* output: btree record */ int *stat) /* output: success/failure */ { struct xfs_btree_block *block; /* btree block */ struct xfs_buf *bp; /* buffer pointer */ int ptr; /* record number */ #ifdef DEBUG int error; /* error return value */ #endif ptr = cur->bc_ptrs[0]; block = xfs_btree_get_block(cur, 0, &bp); #ifdef DEBUG error = xfs_btree_check_block(cur, block, 0, bp); if (error) return error; #endif /* * Off the right end or left end, return failure. */ if (ptr > xfs_btree_get_numrecs(block) || ptr <= 0) { *stat = 0; return 0; } /* * Point to the record and extract its data. */ *recp = xfs_btree_rec_addr(cur, ptr, block); *stat = 1; return 0; } /* * Change the owner of a btree. * * The mechanism we use here is ordered buffer logging. Because we don't know * how many buffers were are going to need to modify, we don't really want to * have to make transaction reservations for the worst case of every buffer in a * full size btree as that may be more space that we can fit in the log.... * * We do the btree walk in the most optimal manner possible - we have sibling * pointers so we can just walk all the blocks on each level from left to right * in a single pass, and then move to the next level and do the same. We can * also do readahead on the sibling pointers to get IO moving more quickly, * though for slow disks this is unlikely to make much difference to performance * as the amount of CPU work we have to do before moving to the next block is * relatively small. * * For each btree block that we load, modify the owner appropriately, set the * buffer as an ordered buffer and log it appropriately. We need to ensure that * we mark the region we change dirty so that if the buffer is relogged in * a subsequent transaction the changes we make here as an ordered buffer are * correctly relogged in that transaction. If we are in recovery context, then * just queue the modified buffer as delayed write buffer so the transaction * recovery completion writes the changes to disk. */ static int xfs_btree_block_change_owner( struct xfs_btree_cur *cur, int level, __uint64_t new_owner, struct list_head *buffer_list) { struct xfs_btree_block *block; struct xfs_buf *bp; union xfs_btree_ptr rptr; /* do right sibling readahead */ xfs_btree_readahead(cur, level, XFS_BTCUR_RIGHTRA); /* modify the owner */ block = xfs_btree_get_block(cur, level, &bp); if (cur->bc_flags & XFS_BTREE_LONG_PTRS) block->bb_u.l.bb_owner = cpu_to_be64(new_owner); else block->bb_u.s.bb_owner = cpu_to_be32(new_owner); /* * If the block is a root block hosted in an inode, we might not have a * buffer pointer here and we shouldn't attempt to log the change as the * information is already held in the inode and discarded when the root * block is formatted into the on-disk inode fork. We still change it, * though, so everything is consistent in memory. */ if (bp) { if (cur->bc_tp) { xfs_trans_ordered_buf(cur->bc_tp, bp); xfs_btree_log_block(cur, bp, XFS_BB_OWNER); } else { xfs_buf_delwri_queue(bp, buffer_list); } } else { ASSERT(cur->bc_flags & XFS_BTREE_ROOT_IN_INODE); ASSERT(level == cur->bc_nlevels - 1); } /* now read rh sibling block for next iteration */ xfs_btree_get_sibling(cur, block, &rptr, XFS_BB_RIGHTSIB); if (xfs_btree_ptr_is_null(cur, &rptr)) return -ENOENT; return xfs_btree_lookup_get_block(cur, level, &rptr, &block); } int xfs_btree_change_owner( struct xfs_btree_cur *cur, __uint64_t new_owner, struct list_head *buffer_list) { union xfs_btree_ptr lptr; int level; struct xfs_btree_block *block = NULL; int error = 0; cur->bc_ops->init_ptr_from_cur(cur, &lptr); /* for each level */ for (level = cur->bc_nlevels - 1; level >= 0; level--) { /* grab the left hand block */ error = xfs_btree_lookup_get_block(cur, level, &lptr, &block); if (error) return error; /* readahead the left most block for the next level down */ if (level > 0) { union xfs_btree_ptr *ptr; ptr = xfs_btree_ptr_addr(cur, 1, block); xfs_btree_readahead_ptr(cur, ptr, 1); /* save for the next iteration of the loop */ lptr = *ptr; } /* for each buffer in the level */ do { error = xfs_btree_block_change_owner(cur, level, new_owner, buffer_list); } while (!error); if (error != -ENOENT) return error; } return 0; } partclone-0.2.86/src/xfs/xfs_btree.h000066400000000000000000000345721262102574200173330ustar00rootroot00000000000000/* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __XFS_BTREE_H__ #define __XFS_BTREE_H__ struct xfs_buf; struct xfs_bmap_free; struct xfs_inode; struct xfs_mount; struct xfs_trans; extern kmem_zone_t *xfs_btree_cur_zone; /* * Generic key, ptr and record wrapper structures. * * These are disk format structures, and are converted where necessary * by the btree specific code that needs to interpret them. */ union xfs_btree_ptr { __be32 s; /* short form ptr */ __be64 l; /* long form ptr */ }; union xfs_btree_key { xfs_bmbt_key_t bmbt; xfs_bmdr_key_t bmbr; /* bmbt root block */ xfs_alloc_key_t alloc; xfs_inobt_key_t inobt; }; union xfs_btree_rec { xfs_bmbt_rec_t bmbt; xfs_bmdr_rec_t bmbr; /* bmbt root block */ xfs_alloc_rec_t alloc; xfs_inobt_rec_t inobt; }; /* * This nonsense is to make -wlint happy. */ #define XFS_LOOKUP_EQ ((xfs_lookup_t)XFS_LOOKUP_EQi) #define XFS_LOOKUP_LE ((xfs_lookup_t)XFS_LOOKUP_LEi) #define XFS_LOOKUP_GE ((xfs_lookup_t)XFS_LOOKUP_GEi) #define XFS_BTNUM_BNO ((xfs_btnum_t)XFS_BTNUM_BNOi) #define XFS_BTNUM_CNT ((xfs_btnum_t)XFS_BTNUM_CNTi) #define XFS_BTNUM_BMAP ((xfs_btnum_t)XFS_BTNUM_BMAPi) #define XFS_BTNUM_INO ((xfs_btnum_t)XFS_BTNUM_INOi) #define XFS_BTNUM_FINO ((xfs_btnum_t)XFS_BTNUM_FINOi) /* * For logging record fields. */ #define XFS_BB_MAGIC (1 << 0) #define XFS_BB_LEVEL (1 << 1) #define XFS_BB_NUMRECS (1 << 2) #define XFS_BB_LEFTSIB (1 << 3) #define XFS_BB_RIGHTSIB (1 << 4) #define XFS_BB_BLKNO (1 << 5) #define XFS_BB_LSN (1 << 6) #define XFS_BB_UUID (1 << 7) #define XFS_BB_OWNER (1 << 8) #define XFS_BB_NUM_BITS 5 #define XFS_BB_ALL_BITS ((1 << XFS_BB_NUM_BITS) - 1) #define XFS_BB_NUM_BITS_CRC 9 #define XFS_BB_ALL_BITS_CRC ((1 << XFS_BB_NUM_BITS_CRC) - 1) /* * Generic stats interface */ #define __XFS_BTREE_STATS_INC(type, stat) \ XFS_STATS_INC(xs_ ## type ## _2_ ## stat) #define XFS_BTREE_STATS_INC(cur, stat) \ do { \ switch (cur->bc_btnum) { \ case XFS_BTNUM_BNO: __XFS_BTREE_STATS_INC(abtb, stat); break; \ case XFS_BTNUM_CNT: __XFS_BTREE_STATS_INC(abtc, stat); break; \ case XFS_BTNUM_BMAP: __XFS_BTREE_STATS_INC(bmbt, stat); break; \ case XFS_BTNUM_INO: __XFS_BTREE_STATS_INC(ibt, stat); break; \ case XFS_BTNUM_FINO: __XFS_BTREE_STATS_INC(fibt, stat); break; \ case XFS_BTNUM_MAX: ASSERT(0); /* fucking gcc */ ; break; \ } \ } while (0) #define __XFS_BTREE_STATS_ADD(type, stat, val) \ XFS_STATS_ADD(xs_ ## type ## _2_ ## stat, val) #define XFS_BTREE_STATS_ADD(cur, stat, val) \ do { \ switch (cur->bc_btnum) { \ case XFS_BTNUM_BNO: __XFS_BTREE_STATS_ADD(abtb, stat, val); break; \ case XFS_BTNUM_CNT: __XFS_BTREE_STATS_ADD(abtc, stat, val); break; \ case XFS_BTNUM_BMAP: __XFS_BTREE_STATS_ADD(bmbt, stat, val); break; \ case XFS_BTNUM_INO: __XFS_BTREE_STATS_ADD(ibt, stat, val); break; \ case XFS_BTNUM_FINO: __XFS_BTREE_STATS_ADD(fibt, stat, val); break; \ case XFS_BTNUM_MAX: ASSERT(0); /* fucking gcc */ ; break; \ } \ } while (0) #define XFS_BTREE_MAXLEVELS 8 /* max of all btrees */ struct xfs_btree_ops { /* size of the key and record structures */ size_t key_len; size_t rec_len; /* cursor operations */ struct xfs_btree_cur *(*dup_cursor)(struct xfs_btree_cur *); void (*update_cursor)(struct xfs_btree_cur *src, struct xfs_btree_cur *dst); /* update btree root pointer */ void (*set_root)(struct xfs_btree_cur *cur, union xfs_btree_ptr *nptr, int level_change); /* block allocation / freeing */ int (*alloc_block)(struct xfs_btree_cur *cur, union xfs_btree_ptr *start_bno, union xfs_btree_ptr *new_bno, int *stat); int (*free_block)(struct xfs_btree_cur *cur, struct xfs_buf *bp); /* update last record information */ void (*update_lastrec)(struct xfs_btree_cur *cur, struct xfs_btree_block *block, union xfs_btree_rec *rec, int ptr, int reason); /* records in block/level */ int (*get_minrecs)(struct xfs_btree_cur *cur, int level); int (*get_maxrecs)(struct xfs_btree_cur *cur, int level); /* records on disk. Matter for the root in inode case. */ int (*get_dmaxrecs)(struct xfs_btree_cur *cur, int level); /* init values of btree structures */ void (*init_key_from_rec)(union xfs_btree_key *key, union xfs_btree_rec *rec); void (*init_rec_from_key)(union xfs_btree_key *key, union xfs_btree_rec *rec); void (*init_rec_from_cur)(struct xfs_btree_cur *cur, union xfs_btree_rec *rec); void (*init_ptr_from_cur)(struct xfs_btree_cur *cur, union xfs_btree_ptr *ptr); /* difference between key value and cursor value */ __int64_t (*key_diff)(struct xfs_btree_cur *cur, union xfs_btree_key *key); const struct xfs_buf_ops *buf_ops; #if defined(DEBUG) || defined(XFS_WARN) /* check that k1 is lower than k2 */ int (*keys_inorder)(struct xfs_btree_cur *cur, union xfs_btree_key *k1, union xfs_btree_key *k2); /* check that r1 is lower than r2 */ int (*recs_inorder)(struct xfs_btree_cur *cur, union xfs_btree_rec *r1, union xfs_btree_rec *r2); #endif }; /* * Reasons for the update_lastrec method to be called. */ #define LASTREC_UPDATE 0 #define LASTREC_INSREC 1 #define LASTREC_DELREC 2 /* * Btree cursor structure. * This collects all information needed by the btree code in one place. */ typedef struct xfs_btree_cur { struct xfs_trans *bc_tp; /* transaction we're in, if any */ struct xfs_mount *bc_mp; /* file system mount struct */ const struct xfs_btree_ops *bc_ops; uint bc_flags; /* btree features - below */ union { xfs_alloc_rec_incore_t a; xfs_bmbt_irec_t b; xfs_inobt_rec_incore_t i; } bc_rec; /* current insert/search record value */ struct xfs_buf *bc_bufs[XFS_BTREE_MAXLEVELS]; /* buf ptr per level */ int bc_ptrs[XFS_BTREE_MAXLEVELS]; /* key/record # */ __uint8_t bc_ra[XFS_BTREE_MAXLEVELS]; /* readahead bits */ #define XFS_BTCUR_LEFTRA 1 /* left sibling has been read-ahead */ #define XFS_BTCUR_RIGHTRA 2 /* right sibling has been read-ahead */ __uint8_t bc_nlevels; /* number of levels in the tree */ __uint8_t bc_blocklog; /* log2(blocksize) of btree blocks */ xfs_btnum_t bc_btnum; /* identifies which btree type */ union { struct { /* needed for BNO, CNT, INO */ struct xfs_buf *agbp; /* agf/agi buffer pointer */ xfs_agnumber_t agno; /* ag number */ } a; struct { /* needed for BMAP */ struct xfs_inode *ip; /* pointer to our inode */ struct xfs_bmap_free *flist; /* list to free after */ xfs_fsblock_t firstblock; /* 1st blk allocated */ int allocated; /* count of alloced */ short forksize; /* fork's inode space */ char whichfork; /* data or attr fork */ char flags; /* flags */ #define XFS_BTCUR_BPRV_WASDEL 1 /* was delayed */ } b; } bc_private; /* per-btree type data */ } xfs_btree_cur_t; /* cursor flags */ #define XFS_BTREE_LONG_PTRS (1<<0) /* pointers are 64bits long */ #define XFS_BTREE_ROOT_IN_INODE (1<<1) /* root may be variable size */ #define XFS_BTREE_LASTREC_UPDATE (1<<2) /* track last rec externally */ #define XFS_BTREE_CRC_BLOCKS (1<<3) /* uses extended btree blocks */ #define XFS_BTREE_NOERROR 0 #define XFS_BTREE_ERROR 1 /* * Convert from buffer to btree block header. */ #define XFS_BUF_TO_BLOCK(bp) ((struct xfs_btree_block *)((bp)->b_addr)) /* * Check that block header is ok. */ int xfs_btree_check_block( struct xfs_btree_cur *cur, /* btree cursor */ struct xfs_btree_block *block, /* generic btree block pointer */ int level, /* level of the btree block */ struct xfs_buf *bp); /* buffer containing block, if any */ /* * Check that (long) pointer is ok. */ int /* error (0 or EFSCORRUPTED) */ xfs_btree_check_lptr( struct xfs_btree_cur *cur, /* btree cursor */ xfs_fsblock_t ptr, /* btree block disk address */ int level); /* btree block level */ /* * Delete the btree cursor. */ void xfs_btree_del_cursor( xfs_btree_cur_t *cur, /* btree cursor */ int error); /* del because of error */ /* * Duplicate the btree cursor. * Allocate a new one, copy the record, re-get the buffers. */ int /* error */ xfs_btree_dup_cursor( xfs_btree_cur_t *cur, /* input cursor */ xfs_btree_cur_t **ncur);/* output cursor */ /* * Get a buffer for the block, return it with no data read. * Long-form addressing. */ struct xfs_buf * /* buffer for fsbno */ xfs_btree_get_bufl( struct xfs_mount *mp, /* file system mount point */ struct xfs_trans *tp, /* transaction pointer */ xfs_fsblock_t fsbno, /* file system block number */ uint lock); /* lock flags for get_buf */ /* * Get a buffer for the block, return it with no data read. * Short-form addressing. */ struct xfs_buf * /* buffer for agno/agbno */ xfs_btree_get_bufs( struct xfs_mount *mp, /* file system mount point */ struct xfs_trans *tp, /* transaction pointer */ xfs_agnumber_t agno, /* allocation group number */ xfs_agblock_t agbno, /* allocation group block number */ uint lock); /* lock flags for get_buf */ /* * Check for the cursor referring to the last block at the given level. */ int /* 1=is last block, 0=not last block */ xfs_btree_islastblock( xfs_btree_cur_t *cur, /* btree cursor */ int level); /* level to check */ /* * Compute first and last byte offsets for the fields given. * Interprets the offsets table, which contains struct field offsets. */ void xfs_btree_offsets( __int64_t fields, /* bitmask of fields */ const short *offsets,/* table of field offsets */ int nbits, /* number of bits to inspect */ int *first, /* output: first byte offset */ int *last); /* output: last byte offset */ /* * Get a buffer for the block, return it read in. * Long-form addressing. */ int /* error */ xfs_btree_read_bufl( struct xfs_mount *mp, /* file system mount point */ struct xfs_trans *tp, /* transaction pointer */ xfs_fsblock_t fsbno, /* file system block number */ uint lock, /* lock flags for read_buf */ struct xfs_buf **bpp, /* buffer for fsbno */ int refval, /* ref count value for buffer */ const struct xfs_buf_ops *ops); /* * Read-ahead the block, don't wait for it, don't return a buffer. * Long-form addressing. */ void /* error */ xfs_btree_reada_bufl( struct xfs_mount *mp, /* file system mount point */ xfs_fsblock_t fsbno, /* file system block number */ xfs_extlen_t count, /* count of filesystem blocks */ const struct xfs_buf_ops *ops); /* * Read-ahead the block, don't wait for it, don't return a buffer. * Short-form addressing. */ void /* error */ xfs_btree_reada_bufs( struct xfs_mount *mp, /* file system mount point */ xfs_agnumber_t agno, /* allocation group number */ xfs_agblock_t agbno, /* allocation group block number */ xfs_extlen_t count, /* count of filesystem blocks */ const struct xfs_buf_ops *ops); /* * Initialise a new btree block header */ void xfs_btree_init_block( struct xfs_mount *mp, struct xfs_buf *bp, __u32 magic, __u16 level, __u16 numrecs, __u64 owner, unsigned int flags); void xfs_btree_init_block_int( struct xfs_mount *mp, struct xfs_btree_block *buf, xfs_daddr_t blkno, __u32 magic, __u16 level, __u16 numrecs, __u64 owner, unsigned int flags); /* * Common btree core entry points. */ int xfs_btree_increment(struct xfs_btree_cur *, int, int *); int xfs_btree_decrement(struct xfs_btree_cur *, int, int *); int xfs_btree_lookup(struct xfs_btree_cur *, xfs_lookup_t, int *); int xfs_btree_update(struct xfs_btree_cur *, union xfs_btree_rec *); int xfs_btree_new_iroot(struct xfs_btree_cur *, int *, int *); int xfs_btree_insert(struct xfs_btree_cur *, int *); int xfs_btree_delete(struct xfs_btree_cur *, int *); int xfs_btree_get_rec(struct xfs_btree_cur *, union xfs_btree_rec **, int *); int xfs_btree_change_owner(struct xfs_btree_cur *cur, __uint64_t new_owner, struct list_head *buffer_list); /* * btree block CRC helpers */ void xfs_btree_lblock_calc_crc(struct xfs_buf *); bool xfs_btree_lblock_verify_crc(struct xfs_buf *); void xfs_btree_sblock_calc_crc(struct xfs_buf *); bool xfs_btree_sblock_verify_crc(struct xfs_buf *); /* * Internal btree helpers also used by xfs_bmap.c. */ void xfs_btree_log_block(struct xfs_btree_cur *, struct xfs_buf *, int); void xfs_btree_log_recs(struct xfs_btree_cur *, struct xfs_buf *, int, int); /* * Helpers. */ static inline int xfs_btree_get_numrecs(struct xfs_btree_block *block) { return be16_to_cpu(block->bb_numrecs); } static inline void xfs_btree_set_numrecs(struct xfs_btree_block *block, __uint16_t numrecs) { block->bb_numrecs = cpu_to_be16(numrecs); } static inline int xfs_btree_get_level(struct xfs_btree_block *block) { return be16_to_cpu(block->bb_level); } /* * Min and max functions for extlen, agblock, fileoff, and filblks types. */ #define XFS_EXTLEN_MIN(a,b) min_t(xfs_extlen_t, (a), (b)) #define XFS_EXTLEN_MAX(a,b) max_t(xfs_extlen_t, (a), (b)) #define XFS_AGBLOCK_MIN(a,b) min_t(xfs_agblock_t, (a), (b)) #define XFS_AGBLOCK_MAX(a,b) max_t(xfs_agblock_t, (a), (b)) #define XFS_FILEOFF_MIN(a,b) min_t(xfs_fileoff_t, (a), (b)) #define XFS_FILEOFF_MAX(a,b) max_t(xfs_fileoff_t, (a), (b)) #define XFS_FILBLKS_MIN(a,b) min_t(xfs_filblks_t, (a), (b)) #define XFS_FILBLKS_MAX(a,b) max_t(xfs_filblks_t, (a), (b)) #define XFS_FSB_SANITY_CHECK(mp,fsb) \ (XFS_FSB_TO_AGNO(mp, fsb) < mp->m_sb.sb_agcount && \ XFS_FSB_TO_AGBNO(mp, fsb) < mp->m_sb.sb_agblocks) /* * Trace hooks. Currently not implemented as they need to be ported * over to the generic tracing functionality, which is some effort. * * i,j = integer (32 bit) * b = btree block buffer (xfs_buf_t) * p = btree ptr * r = btree record * k = btree key */ #define XFS_BTREE_TRACE_ARGBI(c, b, i) #define XFS_BTREE_TRACE_ARGBII(c, b, i, j) #define XFS_BTREE_TRACE_ARGI(c, i) #define XFS_BTREE_TRACE_ARGIPK(c, i, p, s) #define XFS_BTREE_TRACE_ARGIPR(c, i, p, r) #define XFS_BTREE_TRACE_ARGIK(c, i, k) #define XFS_BTREE_TRACE_ARGR(c, r) #define XFS_BTREE_TRACE_CURSOR(c, t) #endif /* __XFS_BTREE_H__ */ partclone-0.2.86/src/xfs/xfs_btree_trace.h000066400000000000000000000064621262102574200205060ustar00rootroot00000000000000/* * Copyright (c) 2008 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __XFS_BTREE_TRACE_H__ #define __XFS_BTREE_TRACE_H__ struct xfs_btree_cur; struct xfs_buf; /* * Trace hooks. * i,j = integer (32 bit) * b = btree block buffer (xfs_buf_t) * p = btree ptr * r = btree record * k = btree key */ #ifdef XFS_BTREE_TRACE /* * Trace buffer entry types. */ #define XFS_BTREE_KTRACE_ARGBI 1 #define XFS_BTREE_KTRACE_ARGBII 2 #define XFS_BTREE_KTRACE_ARGFFFI 3 #define XFS_BTREE_KTRACE_ARGI 4 #define XFS_BTREE_KTRACE_ARGIPK 5 #define XFS_BTREE_KTRACE_ARGIPR 6 #define XFS_BTREE_KTRACE_ARGIK 7 #define XFS_BTREE_KTRACE_ARGR 8 #define XFS_BTREE_KTRACE_CUR 9 /* * Sub-types for cursor traces. */ #define XBT_ARGS 0 #define XBT_ENTRY 1 #define XBT_ERROR 2 #define XBT_EXIT 3 void xfs_btree_trace_argbi(const char *, struct xfs_btree_cur *, struct xfs_buf *, int, int); void xfs_btree_trace_argbii(const char *, struct xfs_btree_cur *, struct xfs_buf *, int, int, int); void xfs_btree_trace_argi(const char *, struct xfs_btree_cur *, int, int); void xfs_btree_trace_argipk(const char *, struct xfs_btree_cur *, int, union xfs_btree_ptr, union xfs_btree_key *, int); void xfs_btree_trace_argipr(const char *, struct xfs_btree_cur *, int, union xfs_btree_ptr, union xfs_btree_rec *, int); void xfs_btree_trace_argik(const char *, struct xfs_btree_cur *, int, union xfs_btree_key *, int); void xfs_btree_trace_argr(const char *, struct xfs_btree_cur *, union xfs_btree_rec *, int); void xfs_btree_trace_cursor(const char *, struct xfs_btree_cur *, int, int); #define XFS_BTREE_TRACE_ARGBI(c, b, i) \ xfs_btree_trace_argbi(__func__, c, b, i, __LINE__) #define XFS_BTREE_TRACE_ARGBII(c, b, i, j) \ xfs_btree_trace_argbii(__func__, c, b, i, j, __LINE__) #define XFS_BTREE_TRACE_ARGI(c, i) \ xfs_btree_trace_argi(__func__, c, i, __LINE__) #define XFS_BTREE_TRACE_ARGIPK(c, i, p, k) \ xfs_btree_trace_argipk(__func__, c, i, p, k, __LINE__) #define XFS_BTREE_TRACE_ARGIPR(c, i, p, r) \ xfs_btree_trace_argipr(__func__, c, i, p, r, __LINE__) #define XFS_BTREE_TRACE_ARGIK(c, i, k) \ xfs_btree_trace_argik(__func__, c, i, k, __LINE__) #define XFS_BTREE_TRACE_ARGR(c, r) \ xfs_btree_trace_argr(__func__, c, r, __LINE__) #define XFS_BTREE_TRACE_CURSOR(c, t) \ xfs_btree_trace_cursor(__func__, c, t, __LINE__) #else #define XFS_BTREE_TRACE_ARGBI(c, b, i) #define XFS_BTREE_TRACE_ARGBII(c, b, i, j) #define XFS_BTREE_TRACE_ARGI(c, i) #define XFS_BTREE_TRACE_ARGIPK(c, i, p, s) #define XFS_BTREE_TRACE_ARGIPR(c, i, p, r) #define XFS_BTREE_TRACE_ARGIK(c, i, k) #define XFS_BTREE_TRACE_ARGR(c, r) #define XFS_BTREE_TRACE_CURSOR(c, t) #endif /* XFS_BTREE_TRACE */ #endif /* __XFS_BTREE_TRACE_H__ */ partclone-0.2.86/src/xfs/xfs_cksum.h000066400000000000000000000031701262102574200173420ustar00rootroot00000000000000#ifndef _XFS_CKSUM_H #define _XFS_CKSUM_H 1 #define XFS_CRC_SEED (~(__uint32_t)0) /* * Calculate the intermediate checksum for a buffer that has the CRC field * inside it. The offset of the 32bit crc fields is passed as the * cksum_offset parameter. */ static inline __uint32_t xfs_start_cksum(char *buffer, size_t length, unsigned long cksum_offset) { __uint32_t zero = 0; __uint32_t crc; /* Calculate CRC up to the checksum. */ crc = crc32c(XFS_CRC_SEED, buffer, cksum_offset); /* Skip checksum field */ crc = crc32c(crc, &zero, sizeof(__u32)); /* Calculate the rest of the CRC. */ return crc32c(crc, &buffer[cksum_offset + sizeof(__be32)], length - (cksum_offset + sizeof(__be32))); } /* * Convert the intermediate checksum to the final ondisk format. * * The CRC32c calculation uses LE format even on BE machines, but returns the * result in host endian format. Hence we need to byte swap it back to LE format * so that it is consistent on disk. */ static inline __le32 xfs_end_cksum(__uint32_t crc) { return ~cpu_to_le32(crc); } /* * Helper to generate the checksum for a buffer. */ static inline void xfs_update_cksum(char *buffer, size_t length, unsigned long cksum_offset) { __uint32_t crc = xfs_start_cksum(buffer, length, cksum_offset); *(__le32 *)(buffer + cksum_offset) = xfs_end_cksum(crc); } /* * Helper to verify the checksum for a buffer. */ static inline int xfs_verify_cksum(char *buffer, size_t length, unsigned long cksum_offset) { __uint32_t crc = xfs_start_cksum(buffer, length, cksum_offset); return *(__le32 *)(buffer + cksum_offset) == xfs_end_cksum(crc); } #endif /* _XFS_CKSUM_H */ partclone-0.2.86/src/xfs/xfs_da_btree.c000066400000000000000000002127331262102574200177670ustar00rootroot00000000000000/* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * Copyright (c) 2013 Red Hat, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_bit.h" #include "xfs_mount.h" #include "xfs_da_format.h" #include "xfs_da_btree.h" #include "xfs_dir2.h" #include "xfs_dir2_priv.h" #include "xfs_inode.h" #include "xfs_trans.h" #include "xfs_alloc.h" #include "xfs_bmap.h" #include "xfs_attr_leaf.h" #include "xfs_trace.h" #include "xfs_cksum.h" /* * xfs_da_btree.c * * Routines to implement directories as Btrees of hashed names. */ /*======================================================================== * Function prototypes for the kernel. *========================================================================*/ /* * Routines used for growing the Btree. */ STATIC int xfs_da3_root_split(xfs_da_state_t *state, xfs_da_state_blk_t *existing_root, xfs_da_state_blk_t *new_child); STATIC int xfs_da3_node_split(xfs_da_state_t *state, xfs_da_state_blk_t *existing_blk, xfs_da_state_blk_t *split_blk, xfs_da_state_blk_t *blk_to_add, int treelevel, int *result); STATIC void xfs_da3_node_rebalance(xfs_da_state_t *state, xfs_da_state_blk_t *node_blk_1, xfs_da_state_blk_t *node_blk_2); STATIC void xfs_da3_node_add(xfs_da_state_t *state, xfs_da_state_blk_t *old_node_blk, xfs_da_state_blk_t *new_node_blk); /* * Routines used for shrinking the Btree. */ STATIC int xfs_da3_root_join(xfs_da_state_t *state, xfs_da_state_blk_t *root_blk); STATIC int xfs_da3_node_toosmall(xfs_da_state_t *state, int *retval); STATIC void xfs_da3_node_remove(xfs_da_state_t *state, xfs_da_state_blk_t *drop_blk); STATIC void xfs_da3_node_unbalance(xfs_da_state_t *state, xfs_da_state_blk_t *src_node_blk, xfs_da_state_blk_t *dst_node_blk); /* * Utility routines. */ STATIC int xfs_da3_blk_unlink(xfs_da_state_t *state, xfs_da_state_blk_t *drop_blk, xfs_da_state_blk_t *save_blk); kmem_zone_t *xfs_da_state_zone; /* anchor for state struct zone */ /* * Allocate a dir-state structure. * We don't put them on the stack since they're large. */ xfs_da_state_t * xfs_da_state_alloc(void) { return kmem_zone_zalloc(xfs_da_state_zone, KM_NOFS); } /* * Kill the altpath contents of a da-state structure. */ STATIC void xfs_da_state_kill_altpath(xfs_da_state_t *state) { int i; for (i = 0; i < state->altpath.active; i++) state->altpath.blk[i].bp = NULL; state->altpath.active = 0; } /* * Free a da-state structure. */ void xfs_da_state_free(xfs_da_state_t *state) { xfs_da_state_kill_altpath(state); #ifdef DEBUG memset((char *)state, 0, sizeof(*state)); #endif /* DEBUG */ kmem_zone_free(xfs_da_state_zone, state); } static bool xfs_da3_node_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_target->bt_mount; struct xfs_da_intnode *hdr = bp->b_addr; struct xfs_da3_icnode_hdr ichdr; const struct xfs_dir_ops *ops; ops = xfs_dir_get_ops(mp, NULL); ops->node_hdr_from_disk(&ichdr, hdr); if (xfs_sb_version_hascrc(&mp->m_sb)) { struct xfs_da3_node_hdr *hdr3 = bp->b_addr; if (ichdr.magic != XFS_DA3_NODE_MAGIC) return false; if (!uuid_equal(&hdr3->info.uuid, &mp->m_sb.sb_meta_uuid)) return false; if (be64_to_cpu(hdr3->info.blkno) != bp->b_bn) return false; } else { if (ichdr.magic != XFS_DA_NODE_MAGIC) return false; } if (ichdr.level == 0) return false; if (ichdr.level > XFS_DA_NODE_MAXDEPTH) return false; if (ichdr.count == 0) return false; /* * we don't know if the node is for and attribute or directory tree, * so only fail if the count is outside both bounds */ if (ichdr.count > mp->m_dir_geo->node_ents && ichdr.count > mp->m_attr_geo->node_ents) return false; /* XXX: hash order check? */ return true; } static void xfs_da3_node_write_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_target->bt_mount; struct xfs_buf_log_item *bip = bp->b_fspriv; struct xfs_da3_node_hdr *hdr3 = bp->b_addr; if (!xfs_da3_node_verify(bp)) { xfs_buf_ioerror(bp, -EFSCORRUPTED); xfs_verifier_error(bp); return; } if (!xfs_sb_version_hascrc(&mp->m_sb)) return; if (bip) hdr3->info.lsn = cpu_to_be64(bip->bli_item.li_lsn); xfs_buf_update_cksum(bp, XFS_DA3_NODE_CRC_OFF); } /* * leaf/node format detection on trees is sketchy, so a node read can be done on * leaf level blocks when detection identifies the tree as a node format tree * incorrectly. In this case, we need to swap the verifier to match the correct * format of the block being read. */ static void xfs_da3_node_read_verify( struct xfs_buf *bp) { struct xfs_da_blkinfo *info = bp->b_addr; switch (be16_to_cpu(info->magic)) { case XFS_DA3_NODE_MAGIC: if (!xfs_buf_verify_cksum(bp, XFS_DA3_NODE_CRC_OFF)) { xfs_buf_ioerror(bp, -EFSBADCRC); break; } /* fall through */ case XFS_DA_NODE_MAGIC: if (!xfs_da3_node_verify(bp)) { xfs_buf_ioerror(bp, -EFSCORRUPTED); break; } return; case XFS_ATTR_LEAF_MAGIC: case XFS_ATTR3_LEAF_MAGIC: bp->b_ops = &xfs_attr3_leaf_buf_ops; bp->b_ops->verify_read(bp); return; case XFS_DIR2_LEAFN_MAGIC: case XFS_DIR3_LEAFN_MAGIC: bp->b_ops = &xfs_dir3_leafn_buf_ops; bp->b_ops->verify_read(bp); return; default: xfs_buf_ioerror(bp, -EFSCORRUPTED); break; } /* corrupt block */ xfs_verifier_error(bp); } const struct xfs_buf_ops xfs_da3_node_buf_ops = { .verify_read = xfs_da3_node_read_verify, .verify_write = xfs_da3_node_write_verify, }; int xfs_da3_node_read( struct xfs_trans *tp, struct xfs_inode *dp, xfs_dablk_t bno, xfs_daddr_t mappedbno, struct xfs_buf **bpp, int which_fork) { int err; err = xfs_da_read_buf(tp, dp, bno, mappedbno, bpp, which_fork, &xfs_da3_node_buf_ops); if (!err && tp) { struct xfs_da_blkinfo *info = (*bpp)->b_addr; int type; switch (be16_to_cpu(info->magic)) { case XFS_DA_NODE_MAGIC: case XFS_DA3_NODE_MAGIC: type = XFS_BLFT_DA_NODE_BUF; break; case XFS_ATTR_LEAF_MAGIC: case XFS_ATTR3_LEAF_MAGIC: type = XFS_BLFT_ATTR_LEAF_BUF; break; case XFS_DIR2_LEAFN_MAGIC: case XFS_DIR3_LEAFN_MAGIC: type = XFS_BLFT_DIR_LEAFN_BUF; break; default: type = 0; ASSERT(0); break; } xfs_trans_buf_set_type(tp, *bpp, type); } return err; } /*======================================================================== * Routines used for growing the Btree. *========================================================================*/ /* * Create the initial contents of an intermediate node. */ int xfs_da3_node_create( struct xfs_da_args *args, xfs_dablk_t blkno, int level, struct xfs_buf **bpp, int whichfork) { struct xfs_da_intnode *node; struct xfs_trans *tp = args->trans; struct xfs_mount *mp = tp->t_mountp; struct xfs_da3_icnode_hdr ichdr = {0}; struct xfs_buf *bp; int error; struct xfs_inode *dp = args->dp; trace_xfs_da_node_create(args); ASSERT(level <= XFS_DA_NODE_MAXDEPTH); error = xfs_da_get_buf(tp, dp, blkno, -1, &bp, whichfork); if (error) return error; bp->b_ops = &xfs_da3_node_buf_ops; xfs_trans_buf_set_type(tp, bp, XFS_BLFT_DA_NODE_BUF); node = bp->b_addr; if (xfs_sb_version_hascrc(&mp->m_sb)) { struct xfs_da3_node_hdr *hdr3 = bp->b_addr; ichdr.magic = XFS_DA3_NODE_MAGIC; hdr3->info.blkno = cpu_to_be64(bp->b_bn); hdr3->info.owner = cpu_to_be64(args->dp->i_ino); uuid_copy(&hdr3->info.uuid, &mp->m_sb.sb_meta_uuid); } else { ichdr.magic = XFS_DA_NODE_MAGIC; } ichdr.level = level; dp->d_ops->node_hdr_to_disk(node, &ichdr); xfs_trans_log_buf(tp, bp, XFS_DA_LOGRANGE(node, &node->hdr, dp->d_ops->node_hdr_size)); *bpp = bp; return 0; } /* * Split a leaf node, rebalance, then possibly split * intermediate nodes, rebalance, etc. */ int /* error */ xfs_da3_split( struct xfs_da_state *state) { struct xfs_da_state_blk *oldblk; struct xfs_da_state_blk *newblk; struct xfs_da_state_blk *addblk; struct xfs_da_intnode *node; struct xfs_buf *bp; int max; int action = 0; int error; int i; trace_xfs_da_split(state->args); /* * Walk back up the tree splitting/inserting/adjusting as necessary. * If we need to insert and there isn't room, split the node, then * decide which fragment to insert the new block from below into. * Note that we may split the root this way, but we need more fixup. */ max = state->path.active - 1; ASSERT((max >= 0) && (max < XFS_DA_NODE_MAXDEPTH)); ASSERT(state->path.blk[max].magic == XFS_ATTR_LEAF_MAGIC || state->path.blk[max].magic == XFS_DIR2_LEAFN_MAGIC); addblk = &state->path.blk[max]; /* initial dummy value */ for (i = max; (i >= 0) && addblk; state->path.active--, i--) { oldblk = &state->path.blk[i]; newblk = &state->altpath.blk[i]; /* * If a leaf node then * Allocate a new leaf node, then rebalance across them. * else if an intermediate node then * We split on the last layer, must we split the node? */ switch (oldblk->magic) { case XFS_ATTR_LEAF_MAGIC: error = xfs_attr3_leaf_split(state, oldblk, newblk); if ((error != 0) && (error != -ENOSPC)) { return error; /* GROT: attr is inconsistent */ } if (!error) { addblk = newblk; break; } /* * Entry wouldn't fit, split the leaf again. */ state->extravalid = 1; if (state->inleaf) { state->extraafter = 0; /* before newblk */ trace_xfs_attr_leaf_split_before(state->args); error = xfs_attr3_leaf_split(state, oldblk, &state->extrablk); } else { state->extraafter = 1; /* after newblk */ trace_xfs_attr_leaf_split_after(state->args); error = xfs_attr3_leaf_split(state, newblk, &state->extrablk); } if (error) return error; /* GROT: attr inconsistent */ addblk = newblk; break; case XFS_DIR2_LEAFN_MAGIC: error = xfs_dir2_leafn_split(state, oldblk, newblk); if (error) return error; addblk = newblk; break; case XFS_DA_NODE_MAGIC: error = xfs_da3_node_split(state, oldblk, newblk, addblk, max - i, &action); addblk->bp = NULL; if (error) return error; /* GROT: dir is inconsistent */ /* * Record the newly split block for the next time thru? */ if (action) addblk = newblk; else addblk = NULL; break; } /* * Update the btree to show the new hashval for this child. */ xfs_da3_fixhashpath(state, &state->path); } if (!addblk) return 0; /* * Split the root node. */ ASSERT(state->path.active == 0); oldblk = &state->path.blk[0]; error = xfs_da3_root_split(state, oldblk, addblk); if (error) { addblk->bp = NULL; return error; /* GROT: dir is inconsistent */ } /* * Update pointers to the node which used to be block 0 and * just got bumped because of the addition of a new root node. * There might be three blocks involved if a double split occurred, * and the original block 0 could be at any position in the list. * * Note: the magic numbers and sibling pointers are in the same * physical place for both v2 and v3 headers (by design). Hence it * doesn't matter which version of the xfs_da_intnode structure we use * here as the result will be the same using either structure. */ node = oldblk->bp->b_addr; if (node->hdr.info.forw) { if (be32_to_cpu(node->hdr.info.forw) == addblk->blkno) { bp = addblk->bp; } else { ASSERT(state->extravalid); bp = state->extrablk.bp; } node = bp->b_addr; node->hdr.info.back = cpu_to_be32(oldblk->blkno); xfs_trans_log_buf(state->args->trans, bp, XFS_DA_LOGRANGE(node, &node->hdr.info, sizeof(node->hdr.info))); } node = oldblk->bp->b_addr; if (node->hdr.info.back) { if (be32_to_cpu(node->hdr.info.back) == addblk->blkno) { bp = addblk->bp; } else { ASSERT(state->extravalid); bp = state->extrablk.bp; } node = bp->b_addr; node->hdr.info.forw = cpu_to_be32(oldblk->blkno); xfs_trans_log_buf(state->args->trans, bp, XFS_DA_LOGRANGE(node, &node->hdr.info, sizeof(node->hdr.info))); } addblk->bp = NULL; return 0; } /* * Split the root. We have to create a new root and point to the two * parts (the split old root) that we just created. Copy block zero to * the EOF, extending the inode in process. */ STATIC int /* error */ xfs_da3_root_split( struct xfs_da_state *state, struct xfs_da_state_blk *blk1, struct xfs_da_state_blk *blk2) { struct xfs_da_intnode *node; struct xfs_da_intnode *oldroot; struct xfs_da_node_entry *btree; struct xfs_da3_icnode_hdr nodehdr; struct xfs_da_args *args; struct xfs_buf *bp; struct xfs_inode *dp; struct xfs_trans *tp; struct xfs_dir2_leaf *leaf; xfs_dablk_t blkno; int level; int error; int size; trace_xfs_da_root_split(state->args); /* * Copy the existing (incorrect) block from the root node position * to a free space somewhere. */ args = state->args; error = xfs_da_grow_inode(args, &blkno); if (error) return error; dp = args->dp; tp = args->trans; error = xfs_da_get_buf(tp, dp, blkno, -1, &bp, args->whichfork); if (error) return error; node = bp->b_addr; oldroot = blk1->bp->b_addr; if (oldroot->hdr.info.magic == cpu_to_be16(XFS_DA_NODE_MAGIC) || oldroot->hdr.info.magic == cpu_to_be16(XFS_DA3_NODE_MAGIC)) { struct xfs_da3_icnode_hdr icnodehdr; dp->d_ops->node_hdr_from_disk(&icnodehdr, oldroot); btree = dp->d_ops->node_tree_p(oldroot); size = (int)((char *)&btree[icnodehdr.count] - (char *)oldroot); level = icnodehdr.level; /* * we are about to copy oldroot to bp, so set up the type * of bp while we know exactly what it will be. */ xfs_trans_buf_set_type(tp, bp, XFS_BLFT_DA_NODE_BUF); } else { struct xfs_dir3_icleaf_hdr leafhdr; struct xfs_dir2_leaf_entry *ents; leaf = (xfs_dir2_leaf_t *)oldroot; dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf); ents = dp->d_ops->leaf_ents_p(leaf); ASSERT(leafhdr.magic == XFS_DIR2_LEAFN_MAGIC || leafhdr.magic == XFS_DIR3_LEAFN_MAGIC); size = (int)((char *)&ents[leafhdr.count] - (char *)leaf); level = 0; /* * we are about to copy oldroot to bp, so set up the type * of bp while we know exactly what it will be. */ xfs_trans_buf_set_type(tp, bp, XFS_BLFT_DIR_LEAFN_BUF); } /* * we can copy most of the information in the node from one block to * another, but for CRC enabled headers we have to make sure that the * block specific identifiers are kept intact. We update the buffer * directly for this. */ memcpy(node, oldroot, size); if (oldroot->hdr.info.magic == cpu_to_be16(XFS_DA3_NODE_MAGIC) || oldroot->hdr.info.magic == cpu_to_be16(XFS_DIR3_LEAFN_MAGIC)) { struct xfs_da3_intnode *node3 = (struct xfs_da3_intnode *)node; node3->hdr.info.blkno = cpu_to_be64(bp->b_bn); } xfs_trans_log_buf(tp, bp, 0, size - 1); bp->b_ops = blk1->bp->b_ops; xfs_trans_buf_copy_type(bp, blk1->bp); blk1->bp = bp; blk1->blkno = blkno; /* * Set up the new root node. */ error = xfs_da3_node_create(args, (args->whichfork == XFS_DATA_FORK) ? args->geo->leafblk : 0, level + 1, &bp, args->whichfork); if (error) return error; node = bp->b_addr; dp->d_ops->node_hdr_from_disk(&nodehdr, node); btree = dp->d_ops->node_tree_p(node); btree[0].hashval = cpu_to_be32(blk1->hashval); btree[0].before = cpu_to_be32(blk1->blkno); btree[1].hashval = cpu_to_be32(blk2->hashval); btree[1].before = cpu_to_be32(blk2->blkno); nodehdr.count = 2; dp->d_ops->node_hdr_to_disk(node, &nodehdr); #ifdef DEBUG if (oldroot->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC) || oldroot->hdr.info.magic == cpu_to_be16(XFS_DIR3_LEAFN_MAGIC)) { ASSERT(blk1->blkno >= args->geo->leafblk && blk1->blkno < args->geo->freeblk); ASSERT(blk2->blkno >= args->geo->leafblk && blk2->blkno < args->geo->freeblk); } #endif /* Header is already logged by xfs_da_node_create */ xfs_trans_log_buf(tp, bp, XFS_DA_LOGRANGE(node, btree, sizeof(xfs_da_node_entry_t) * 2)); return 0; } /* * Split the node, rebalance, then add the new entry. */ STATIC int /* error */ xfs_da3_node_split( struct xfs_da_state *state, struct xfs_da_state_blk *oldblk, struct xfs_da_state_blk *newblk, struct xfs_da_state_blk *addblk, int treelevel, int *result) { struct xfs_da_intnode *node; struct xfs_da3_icnode_hdr nodehdr; xfs_dablk_t blkno; int newcount; int error; int useextra; struct xfs_inode *dp = state->args->dp; trace_xfs_da_node_split(state->args); node = oldblk->bp->b_addr; dp->d_ops->node_hdr_from_disk(&nodehdr, node); /* * With V2 dirs the extra block is data or freespace. */ useextra = state->extravalid && state->args->whichfork == XFS_ATTR_FORK; newcount = 1 + useextra; /* * Do we have to split the node? */ if (nodehdr.count + newcount > state->args->geo->node_ents) { /* * Allocate a new node, add to the doubly linked chain of * nodes, then move some of our excess entries into it. */ error = xfs_da_grow_inode(state->args, &blkno); if (error) return error; /* GROT: dir is inconsistent */ error = xfs_da3_node_create(state->args, blkno, treelevel, &newblk->bp, state->args->whichfork); if (error) return error; /* GROT: dir is inconsistent */ newblk->blkno = blkno; newblk->magic = XFS_DA_NODE_MAGIC; xfs_da3_node_rebalance(state, oldblk, newblk); error = xfs_da3_blk_link(state, oldblk, newblk); if (error) return error; *result = 1; } else { *result = 0; } /* * Insert the new entry(s) into the correct block * (updating last hashval in the process). * * xfs_da3_node_add() inserts BEFORE the given index, * and as a result of using node_lookup_int() we always * point to a valid entry (not after one), but a split * operation always results in a new block whose hashvals * FOLLOW the current block. * * If we had double-split op below us, then add the extra block too. */ node = oldblk->bp->b_addr; dp->d_ops->node_hdr_from_disk(&nodehdr, node); if (oldblk->index <= nodehdr.count) { oldblk->index++; xfs_da3_node_add(state, oldblk, addblk); if (useextra) { if (state->extraafter) oldblk->index++; xfs_da3_node_add(state, oldblk, &state->extrablk); state->extravalid = 0; } } else { newblk->index++; xfs_da3_node_add(state, newblk, addblk); if (useextra) { if (state->extraafter) newblk->index++; xfs_da3_node_add(state, newblk, &state->extrablk); state->extravalid = 0; } } return 0; } /* * Balance the btree elements between two intermediate nodes, * usually one full and one empty. * * NOTE: if blk2 is empty, then it will get the upper half of blk1. */ STATIC void xfs_da3_node_rebalance( struct xfs_da_state *state, struct xfs_da_state_blk *blk1, struct xfs_da_state_blk *blk2) { struct xfs_da_intnode *node1; struct xfs_da_intnode *node2; struct xfs_da_intnode *tmpnode; struct xfs_da_node_entry *btree1; struct xfs_da_node_entry *btree2; struct xfs_da_node_entry *btree_s; struct xfs_da_node_entry *btree_d; struct xfs_da3_icnode_hdr nodehdr1; struct xfs_da3_icnode_hdr nodehdr2; struct xfs_trans *tp; int count; int tmp; int swap = 0; struct xfs_inode *dp = state->args->dp; trace_xfs_da_node_rebalance(state->args); node1 = blk1->bp->b_addr; node2 = blk2->bp->b_addr; dp->d_ops->node_hdr_from_disk(&nodehdr1, node1); dp->d_ops->node_hdr_from_disk(&nodehdr2, node2); btree1 = dp->d_ops->node_tree_p(node1); btree2 = dp->d_ops->node_tree_p(node2); /* * Figure out how many entries need to move, and in which direction. * Swap the nodes around if that makes it simpler. */ if (nodehdr1.count > 0 && nodehdr2.count > 0 && ((be32_to_cpu(btree2[0].hashval) < be32_to_cpu(btree1[0].hashval)) || (be32_to_cpu(btree2[nodehdr2.count - 1].hashval) < be32_to_cpu(btree1[nodehdr1.count - 1].hashval)))) { tmpnode = node1; node1 = node2; node2 = tmpnode; dp->d_ops->node_hdr_from_disk(&nodehdr1, node1); dp->d_ops->node_hdr_from_disk(&nodehdr2, node2); btree1 = dp->d_ops->node_tree_p(node1); btree2 = dp->d_ops->node_tree_p(node2); swap = 1; } count = (nodehdr1.count - nodehdr2.count) / 2; if (count == 0) return; tp = state->args->trans; /* * Two cases: high-to-low and low-to-high. */ if (count > 0) { /* * Move elements in node2 up to make a hole. */ tmp = nodehdr2.count; if (tmp > 0) { tmp *= (uint)sizeof(xfs_da_node_entry_t); btree_s = &btree2[0]; btree_d = &btree2[count]; memmove(btree_d, btree_s, tmp); } /* * Move the req'd B-tree elements from high in node1 to * low in node2. */ nodehdr2.count += count; tmp = count * (uint)sizeof(xfs_da_node_entry_t); btree_s = &btree1[nodehdr1.count - count]; btree_d = &btree2[0]; memcpy(btree_d, btree_s, tmp); nodehdr1.count -= count; } else { /* * Move the req'd B-tree elements from low in node2 to * high in node1. */ count = -count; tmp = count * (uint)sizeof(xfs_da_node_entry_t); btree_s = &btree2[0]; btree_d = &btree1[nodehdr1.count]; memcpy(btree_d, btree_s, tmp); nodehdr1.count += count; xfs_trans_log_buf(tp, blk1->bp, XFS_DA_LOGRANGE(node1, btree_d, tmp)); /* * Move elements in node2 down to fill the hole. */ tmp = nodehdr2.count - count; tmp *= (uint)sizeof(xfs_da_node_entry_t); btree_s = &btree2[count]; btree_d = &btree2[0]; memmove(btree_d, btree_s, tmp); nodehdr2.count -= count; } /* * Log header of node 1 and all current bits of node 2. */ dp->d_ops->node_hdr_to_disk(node1, &nodehdr1); xfs_trans_log_buf(tp, blk1->bp, XFS_DA_LOGRANGE(node1, &node1->hdr, dp->d_ops->node_hdr_size)); dp->d_ops->node_hdr_to_disk(node2, &nodehdr2); xfs_trans_log_buf(tp, blk2->bp, XFS_DA_LOGRANGE(node2, &node2->hdr, dp->d_ops->node_hdr_size + (sizeof(btree2[0]) * nodehdr2.count))); /* * Record the last hashval from each block for upward propagation. * (note: don't use the swapped node pointers) */ if (swap) { node1 = blk1->bp->b_addr; node2 = blk2->bp->b_addr; dp->d_ops->node_hdr_from_disk(&nodehdr1, node1); dp->d_ops->node_hdr_from_disk(&nodehdr2, node2); btree1 = dp->d_ops->node_tree_p(node1); btree2 = dp->d_ops->node_tree_p(node2); } blk1->hashval = be32_to_cpu(btree1[nodehdr1.count - 1].hashval); blk2->hashval = be32_to_cpu(btree2[nodehdr2.count - 1].hashval); /* * Adjust the expected index for insertion. */ if (blk1->index >= nodehdr1.count) { blk2->index = blk1->index - nodehdr1.count; blk1->index = nodehdr1.count + 1; /* make it invalid */ } } /* * Add a new entry to an intermediate node. */ STATIC void xfs_da3_node_add( struct xfs_da_state *state, struct xfs_da_state_blk *oldblk, struct xfs_da_state_blk *newblk) { struct xfs_da_intnode *node; struct xfs_da3_icnode_hdr nodehdr; struct xfs_da_node_entry *btree; int tmp; struct xfs_inode *dp = state->args->dp; trace_xfs_da_node_add(state->args); node = oldblk->bp->b_addr; dp->d_ops->node_hdr_from_disk(&nodehdr, node); btree = dp->d_ops->node_tree_p(node); ASSERT(oldblk->index >= 0 && oldblk->index <= nodehdr.count); ASSERT(newblk->blkno != 0); if (state->args->whichfork == XFS_DATA_FORK) ASSERT(newblk->blkno >= state->args->geo->leafblk && newblk->blkno < state->args->geo->freeblk); /* * We may need to make some room before we insert the new node. */ tmp = 0; if (oldblk->index < nodehdr.count) { tmp = (nodehdr.count - oldblk->index) * (uint)sizeof(*btree); memmove(&btree[oldblk->index + 1], &btree[oldblk->index], tmp); } btree[oldblk->index].hashval = cpu_to_be32(newblk->hashval); btree[oldblk->index].before = cpu_to_be32(newblk->blkno); xfs_trans_log_buf(state->args->trans, oldblk->bp, XFS_DA_LOGRANGE(node, &btree[oldblk->index], tmp + sizeof(*btree))); nodehdr.count += 1; dp->d_ops->node_hdr_to_disk(node, &nodehdr); xfs_trans_log_buf(state->args->trans, oldblk->bp, XFS_DA_LOGRANGE(node, &node->hdr, dp->d_ops->node_hdr_size)); /* * Copy the last hash value from the oldblk to propagate upwards. */ oldblk->hashval = be32_to_cpu(btree[nodehdr.count - 1].hashval); } /*======================================================================== * Routines used for shrinking the Btree. *========================================================================*/ /* * Deallocate an empty leaf node, remove it from its parent, * possibly deallocating that block, etc... */ int xfs_da3_join( struct xfs_da_state *state) { struct xfs_da_state_blk *drop_blk; struct xfs_da_state_blk *save_blk; int action = 0; int error; trace_xfs_da_join(state->args); drop_blk = &state->path.blk[ state->path.active-1 ]; save_blk = &state->altpath.blk[ state->path.active-1 ]; ASSERT(state->path.blk[0].magic == XFS_DA_NODE_MAGIC); ASSERT(drop_blk->magic == XFS_ATTR_LEAF_MAGIC || drop_blk->magic == XFS_DIR2_LEAFN_MAGIC); /* * Walk back up the tree joining/deallocating as necessary. * When we stop dropping blocks, break out. */ for ( ; state->path.active >= 2; drop_blk--, save_blk--, state->path.active--) { /* * See if we can combine the block with a neighbor. * (action == 0) => no options, just leave * (action == 1) => coalesce, then unlink * (action == 2) => block empty, unlink it */ switch (drop_blk->magic) { case XFS_ATTR_LEAF_MAGIC: error = xfs_attr3_leaf_toosmall(state, &action); if (error) return error; if (action == 0) return 0; xfs_attr3_leaf_unbalance(state, drop_blk, save_blk); break; case XFS_DIR2_LEAFN_MAGIC: error = xfs_dir2_leafn_toosmall(state, &action); if (error) return error; if (action == 0) return 0; xfs_dir2_leafn_unbalance(state, drop_blk, save_blk); break; case XFS_DA_NODE_MAGIC: /* * Remove the offending node, fixup hashvals, * check for a toosmall neighbor. */ xfs_da3_node_remove(state, drop_blk); xfs_da3_fixhashpath(state, &state->path); error = xfs_da3_node_toosmall(state, &action); if (error) return error; if (action == 0) return 0; xfs_da3_node_unbalance(state, drop_blk, save_blk); break; } xfs_da3_fixhashpath(state, &state->altpath); error = xfs_da3_blk_unlink(state, drop_blk, save_blk); xfs_da_state_kill_altpath(state); if (error) return error; error = xfs_da_shrink_inode(state->args, drop_blk->blkno, drop_blk->bp); drop_blk->bp = NULL; if (error) return error; } /* * We joined all the way to the top. If it turns out that * we only have one entry in the root, make the child block * the new root. */ xfs_da3_node_remove(state, drop_blk); xfs_da3_fixhashpath(state, &state->path); error = xfs_da3_root_join(state, &state->path.blk[0]); return error; } #ifdef DEBUG static void xfs_da_blkinfo_onlychild_validate(struct xfs_da_blkinfo *blkinfo, __u16 level) { __be16 magic = blkinfo->magic; if (level == 1) { ASSERT(magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC) || magic == cpu_to_be16(XFS_DIR3_LEAFN_MAGIC) || magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC) || magic == cpu_to_be16(XFS_ATTR3_LEAF_MAGIC)); } else { ASSERT(magic == cpu_to_be16(XFS_DA_NODE_MAGIC) || magic == cpu_to_be16(XFS_DA3_NODE_MAGIC)); } ASSERT(!blkinfo->forw); ASSERT(!blkinfo->back); } #else /* !DEBUG */ #define xfs_da_blkinfo_onlychild_validate(blkinfo, level) #endif /* !DEBUG */ /* * We have only one entry in the root. Copy the only remaining child of * the old root to block 0 as the new root node. */ STATIC int xfs_da3_root_join( struct xfs_da_state *state, struct xfs_da_state_blk *root_blk) { struct xfs_da_intnode *oldroot; struct xfs_da_args *args; xfs_dablk_t child; struct xfs_buf *bp; struct xfs_da3_icnode_hdr oldroothdr; struct xfs_da_node_entry *btree; int error; struct xfs_inode *dp = state->args->dp; trace_xfs_da_root_join(state->args); ASSERT(root_blk->magic == XFS_DA_NODE_MAGIC); args = state->args; oldroot = root_blk->bp->b_addr; dp->d_ops->node_hdr_from_disk(&oldroothdr, oldroot); ASSERT(oldroothdr.forw == 0); ASSERT(oldroothdr.back == 0); /* * If the root has more than one child, then don't do anything. */ if (oldroothdr.count > 1) return 0; /* * Read in the (only) child block, then copy those bytes into * the root block's buffer and free the original child block. */ btree = dp->d_ops->node_tree_p(oldroot); child = be32_to_cpu(btree[0].before); ASSERT(child != 0); error = xfs_da3_node_read(args->trans, dp, child, -1, &bp, args->whichfork); if (error) return error; xfs_da_blkinfo_onlychild_validate(bp->b_addr, oldroothdr.level); /* * This could be copying a leaf back into the root block in the case of * there only being a single leaf block left in the tree. Hence we have * to update the b_ops pointer as well to match the buffer type change * that could occur. For dir3 blocks we also need to update the block * number in the buffer header. */ memcpy(root_blk->bp->b_addr, bp->b_addr, args->geo->blksize); root_blk->bp->b_ops = bp->b_ops; xfs_trans_buf_copy_type(root_blk->bp, bp); if (oldroothdr.magic == XFS_DA3_NODE_MAGIC) { struct xfs_da3_blkinfo *da3 = root_blk->bp->b_addr; da3->blkno = cpu_to_be64(root_blk->bp->b_bn); } xfs_trans_log_buf(args->trans, root_blk->bp, 0, args->geo->blksize - 1); error = xfs_da_shrink_inode(args, child, bp); return error; } /* * Check a node block and its neighbors to see if the block should be * collapsed into one or the other neighbor. Always keep the block * with the smaller block number. * If the current block is over 50% full, don't try to join it, return 0. * If the block is empty, fill in the state structure and return 2. * If it can be collapsed, fill in the state structure and return 1. * If nothing can be done, return 0. */ STATIC int xfs_da3_node_toosmall( struct xfs_da_state *state, int *action) { struct xfs_da_intnode *node; struct xfs_da_state_blk *blk; struct xfs_da_blkinfo *info; xfs_dablk_t blkno; struct xfs_buf *bp; struct xfs_da3_icnode_hdr nodehdr; int count; int forward; int error; int retval; int i; struct xfs_inode *dp = state->args->dp; trace_xfs_da_node_toosmall(state->args); /* * Check for the degenerate case of the block being over 50% full. * If so, it's not worth even looking to see if we might be able * to coalesce with a sibling. */ blk = &state->path.blk[ state->path.active-1 ]; info = blk->bp->b_addr; node = (xfs_da_intnode_t *)info; dp->d_ops->node_hdr_from_disk(&nodehdr, node); if (nodehdr.count > (state->args->geo->node_ents >> 1)) { *action = 0; /* blk over 50%, don't try to join */ return 0; /* blk over 50%, don't try to join */ } /* * Check for the degenerate case of the block being empty. * If the block is empty, we'll simply delete it, no need to * coalesce it with a sibling block. We choose (arbitrarily) * to merge with the forward block unless it is NULL. */ if (nodehdr.count == 0) { /* * Make altpath point to the block we want to keep and * path point to the block we want to drop (this one). */ forward = (info->forw != 0); memcpy(&state->altpath, &state->path, sizeof(state->path)); error = xfs_da3_path_shift(state, &state->altpath, forward, 0, &retval); if (error) return error; if (retval) { *action = 0; } else { *action = 2; } return 0; } /* * Examine each sibling block to see if we can coalesce with * at least 25% free space to spare. We need to figure out * whether to merge with the forward or the backward block. * We prefer coalescing with the lower numbered sibling so as * to shrink a directory over time. */ count = state->args->geo->node_ents; count -= state->args->geo->node_ents >> 2; count -= nodehdr.count; /* start with smaller blk num */ forward = nodehdr.forw < nodehdr.back; for (i = 0; i < 2; forward = !forward, i++) { struct xfs_da3_icnode_hdr thdr; if (forward) blkno = nodehdr.forw; else blkno = nodehdr.back; if (blkno == 0) continue; error = xfs_da3_node_read(state->args->trans, dp, blkno, -1, &bp, state->args->whichfork); if (error) return error; node = bp->b_addr; dp->d_ops->node_hdr_from_disk(&thdr, node); xfs_trans_brelse(state->args->trans, bp); if (count - thdr.count >= 0) break; /* fits with at least 25% to spare */ } if (i >= 2) { *action = 0; return 0; } /* * Make altpath point to the block we want to keep (the lower * numbered block) and path point to the block we want to drop. */ memcpy(&state->altpath, &state->path, sizeof(state->path)); if (blkno < blk->blkno) { error = xfs_da3_path_shift(state, &state->altpath, forward, 0, &retval); } else { error = xfs_da3_path_shift(state, &state->path, forward, 0, &retval); } if (error) return error; if (retval) { *action = 0; return 0; } *action = 1; return 0; } /* * Pick up the last hashvalue from an intermediate node. */ STATIC uint xfs_da3_node_lasthash( struct xfs_inode *dp, struct xfs_buf *bp, int *count) { struct xfs_da_intnode *node; struct xfs_da_node_entry *btree; struct xfs_da3_icnode_hdr nodehdr; node = bp->b_addr; dp->d_ops->node_hdr_from_disk(&nodehdr, node); if (count) *count = nodehdr.count; if (!nodehdr.count) return 0; btree = dp->d_ops->node_tree_p(node); return be32_to_cpu(btree[nodehdr.count - 1].hashval); } /* * Walk back up the tree adjusting hash values as necessary, * when we stop making changes, return. */ void xfs_da3_fixhashpath( struct xfs_da_state *state, struct xfs_da_state_path *path) { struct xfs_da_state_blk *blk; struct xfs_da_intnode *node; struct xfs_da_node_entry *btree; xfs_dahash_t lasthash=0; int level; int count; struct xfs_inode *dp = state->args->dp; trace_xfs_da_fixhashpath(state->args); level = path->active-1; blk = &path->blk[ level ]; switch (blk->magic) { case XFS_ATTR_LEAF_MAGIC: lasthash = xfs_attr_leaf_lasthash(blk->bp, &count); if (count == 0) return; break; case XFS_DIR2_LEAFN_MAGIC: lasthash = xfs_dir2_leafn_lasthash(dp, blk->bp, &count); if (count == 0) return; break; case XFS_DA_NODE_MAGIC: lasthash = xfs_da3_node_lasthash(dp, blk->bp, &count); if (count == 0) return; break; } for (blk--, level--; level >= 0; blk--, level--) { struct xfs_da3_icnode_hdr nodehdr; node = blk->bp->b_addr; dp->d_ops->node_hdr_from_disk(&nodehdr, node); btree = dp->d_ops->node_tree_p(node); if (be32_to_cpu(btree[blk->index].hashval) == lasthash) break; blk->hashval = lasthash; btree[blk->index].hashval = cpu_to_be32(lasthash); xfs_trans_log_buf(state->args->trans, blk->bp, XFS_DA_LOGRANGE(node, &btree[blk->index], sizeof(*btree))); lasthash = be32_to_cpu(btree[nodehdr.count - 1].hashval); } } /* * Remove an entry from an intermediate node. */ STATIC void xfs_da3_node_remove( struct xfs_da_state *state, struct xfs_da_state_blk *drop_blk) { struct xfs_da_intnode *node; struct xfs_da3_icnode_hdr nodehdr; struct xfs_da_node_entry *btree; int index; int tmp; struct xfs_inode *dp = state->args->dp; trace_xfs_da_node_remove(state->args); node = drop_blk->bp->b_addr; dp->d_ops->node_hdr_from_disk(&nodehdr, node); ASSERT(drop_blk->index < nodehdr.count); ASSERT(drop_blk->index >= 0); /* * Copy over the offending entry, or just zero it out. */ index = drop_blk->index; btree = dp->d_ops->node_tree_p(node); if (index < nodehdr.count - 1) { tmp = nodehdr.count - index - 1; tmp *= (uint)sizeof(xfs_da_node_entry_t); memmove(&btree[index], &btree[index + 1], tmp); xfs_trans_log_buf(state->args->trans, drop_blk->bp, XFS_DA_LOGRANGE(node, &btree[index], tmp)); index = nodehdr.count - 1; } memset(&btree[index], 0, sizeof(xfs_da_node_entry_t)); xfs_trans_log_buf(state->args->trans, drop_blk->bp, XFS_DA_LOGRANGE(node, &btree[index], sizeof(btree[index]))); nodehdr.count -= 1; dp->d_ops->node_hdr_to_disk(node, &nodehdr); xfs_trans_log_buf(state->args->trans, drop_blk->bp, XFS_DA_LOGRANGE(node, &node->hdr, dp->d_ops->node_hdr_size)); /* * Copy the last hash value from the block to propagate upwards. */ drop_blk->hashval = be32_to_cpu(btree[index - 1].hashval); } /* * Unbalance the elements between two intermediate nodes, * move all Btree elements from one node into another. */ STATIC void xfs_da3_node_unbalance( struct xfs_da_state *state, struct xfs_da_state_blk *drop_blk, struct xfs_da_state_blk *save_blk) { struct xfs_da_intnode *drop_node; struct xfs_da_intnode *save_node; struct xfs_da_node_entry *drop_btree; struct xfs_da_node_entry *save_btree; struct xfs_da3_icnode_hdr drop_hdr; struct xfs_da3_icnode_hdr save_hdr; struct xfs_trans *tp; int sindex; int tmp; struct xfs_inode *dp = state->args->dp; trace_xfs_da_node_unbalance(state->args); drop_node = drop_blk->bp->b_addr; save_node = save_blk->bp->b_addr; dp->d_ops->node_hdr_from_disk(&drop_hdr, drop_node); dp->d_ops->node_hdr_from_disk(&save_hdr, save_node); drop_btree = dp->d_ops->node_tree_p(drop_node); save_btree = dp->d_ops->node_tree_p(save_node); tp = state->args->trans; /* * If the dying block has lower hashvals, then move all the * elements in the remaining block up to make a hole. */ if ((be32_to_cpu(drop_btree[0].hashval) < be32_to_cpu(save_btree[0].hashval)) || (be32_to_cpu(drop_btree[drop_hdr.count - 1].hashval) < be32_to_cpu(save_btree[save_hdr.count - 1].hashval))) { /* XXX: check this - is memmove dst correct? */ tmp = save_hdr.count * sizeof(xfs_da_node_entry_t); memmove(&save_btree[drop_hdr.count], &save_btree[0], tmp); sindex = 0; xfs_trans_log_buf(tp, save_blk->bp, XFS_DA_LOGRANGE(save_node, &save_btree[0], (save_hdr.count + drop_hdr.count) * sizeof(xfs_da_node_entry_t))); } else { sindex = save_hdr.count; xfs_trans_log_buf(tp, save_blk->bp, XFS_DA_LOGRANGE(save_node, &save_btree[sindex], drop_hdr.count * sizeof(xfs_da_node_entry_t))); } /* * Move all the B-tree elements from drop_blk to save_blk. */ tmp = drop_hdr.count * (uint)sizeof(xfs_da_node_entry_t); memcpy(&save_btree[sindex], &drop_btree[0], tmp); save_hdr.count += drop_hdr.count; dp->d_ops->node_hdr_to_disk(save_node, &save_hdr); xfs_trans_log_buf(tp, save_blk->bp, XFS_DA_LOGRANGE(save_node, &save_node->hdr, dp->d_ops->node_hdr_size)); /* * Save the last hashval in the remaining block for upward propagation. */ save_blk->hashval = be32_to_cpu(save_btree[save_hdr.count - 1].hashval); } /*======================================================================== * Routines used for finding things in the Btree. *========================================================================*/ /* * Walk down the Btree looking for a particular filename, filling * in the state structure as we go. * * We will set the state structure to point to each of the elements * in each of the nodes where either the hashval is or should be. * * We support duplicate hashval's so for each entry in the current * node that could contain the desired hashval, descend. This is a * pruned depth-first tree search. */ int /* error */ xfs_da3_node_lookup_int( struct xfs_da_state *state, int *result) { struct xfs_da_state_blk *blk; struct xfs_da_blkinfo *curr; struct xfs_da_intnode *node; struct xfs_da_node_entry *btree; struct xfs_da3_icnode_hdr nodehdr; struct xfs_da_args *args; xfs_dablk_t blkno; xfs_dahash_t hashval; xfs_dahash_t btreehashval; int probe; int span; int max; int error; int retval; struct xfs_inode *dp = state->args->dp; args = state->args; /* * Descend thru the B-tree searching each level for the right * node to use, until the right hashval is found. */ blkno = (args->whichfork == XFS_DATA_FORK)? args->geo->leafblk : 0; for (blk = &state->path.blk[0], state->path.active = 1; state->path.active <= XFS_DA_NODE_MAXDEPTH; blk++, state->path.active++) { /* * Read the next node down in the tree. */ blk->blkno = blkno; error = xfs_da3_node_read(args->trans, args->dp, blkno, -1, &blk->bp, args->whichfork); if (error) { blk->blkno = 0; state->path.active--; return error; } curr = blk->bp->b_addr; blk->magic = be16_to_cpu(curr->magic); if (blk->magic == XFS_ATTR_LEAF_MAGIC || blk->magic == XFS_ATTR3_LEAF_MAGIC) { blk->magic = XFS_ATTR_LEAF_MAGIC; blk->hashval = xfs_attr_leaf_lasthash(blk->bp, NULL); break; } if (blk->magic == XFS_DIR2_LEAFN_MAGIC || blk->magic == XFS_DIR3_LEAFN_MAGIC) { blk->magic = XFS_DIR2_LEAFN_MAGIC; blk->hashval = xfs_dir2_leafn_lasthash(args->dp, blk->bp, NULL); break; } blk->magic = XFS_DA_NODE_MAGIC; /* * Search an intermediate node for a match. */ node = blk->bp->b_addr; dp->d_ops->node_hdr_from_disk(&nodehdr, node); btree = dp->d_ops->node_tree_p(node); max = nodehdr.count; blk->hashval = be32_to_cpu(btree[max - 1].hashval); /* * Binary search. (note: small blocks will skip loop) */ probe = span = max / 2; hashval = args->hashval; while (span > 4) { span /= 2; btreehashval = be32_to_cpu(btree[probe].hashval); if (btreehashval < hashval) probe += span; else if (btreehashval > hashval) probe -= span; else break; } ASSERT((probe >= 0) && (probe < max)); ASSERT((span <= 4) || (be32_to_cpu(btree[probe].hashval) == hashval)); /* * Since we may have duplicate hashval's, find the first * matching hashval in the node. */ while (probe > 0 && be32_to_cpu(btree[probe].hashval) >= hashval) { probe--; } while (probe < max && be32_to_cpu(btree[probe].hashval) < hashval) { probe++; } /* * Pick the right block to descend on. */ if (probe == max) { blk->index = max - 1; blkno = be32_to_cpu(btree[max - 1].before); } else { blk->index = probe; blkno = be32_to_cpu(btree[probe].before); } } /* * A leaf block that ends in the hashval that we are interested in * (final hashval == search hashval) means that the next block may * contain more entries with the same hashval, shift upward to the * next leaf and keep searching. */ for (;;) { if (blk->magic == XFS_DIR2_LEAFN_MAGIC) { retval = xfs_dir2_leafn_lookup_int(blk->bp, args, &blk->index, state); } else if (blk->magic == XFS_ATTR_LEAF_MAGIC) { retval = xfs_attr3_leaf_lookup_int(blk->bp, args); blk->index = args->index; args->blkno = blk->blkno; } else { ASSERT(0); return -EFSCORRUPTED; } if (((retval == -ENOENT) || (retval == -ENOATTR)) && (blk->hashval == args->hashval)) { error = xfs_da3_path_shift(state, &state->path, 1, 1, &retval); if (error) return error; if (retval == 0) { continue; } else if (blk->magic == XFS_ATTR_LEAF_MAGIC) { /* path_shift() gives ENOENT */ retval = -ENOATTR; } } break; } *result = retval; return 0; } /*======================================================================== * Utility routines. *========================================================================*/ /* * Compare two intermediate nodes for "order". */ STATIC int xfs_da3_node_order( struct xfs_inode *dp, struct xfs_buf *node1_bp, struct xfs_buf *node2_bp) { struct xfs_da_intnode *node1; struct xfs_da_intnode *node2; struct xfs_da_node_entry *btree1; struct xfs_da_node_entry *btree2; struct xfs_da3_icnode_hdr node1hdr; struct xfs_da3_icnode_hdr node2hdr; node1 = node1_bp->b_addr; node2 = node2_bp->b_addr; dp->d_ops->node_hdr_from_disk(&node1hdr, node1); dp->d_ops->node_hdr_from_disk(&node2hdr, node2); btree1 = dp->d_ops->node_tree_p(node1); btree2 = dp->d_ops->node_tree_p(node2); if (node1hdr.count > 0 && node2hdr.count > 0 && ((be32_to_cpu(btree2[0].hashval) < be32_to_cpu(btree1[0].hashval)) || (be32_to_cpu(btree2[node2hdr.count - 1].hashval) < be32_to_cpu(btree1[node1hdr.count - 1].hashval)))) { return 1; } return 0; } /* * Link a new block into a doubly linked list of blocks (of whatever type). */ int /* error */ xfs_da3_blk_link( struct xfs_da_state *state, struct xfs_da_state_blk *old_blk, struct xfs_da_state_blk *new_blk) { struct xfs_da_blkinfo *old_info; struct xfs_da_blkinfo *new_info; struct xfs_da_blkinfo *tmp_info; struct xfs_da_args *args; struct xfs_buf *bp; int before = 0; int error; struct xfs_inode *dp = state->args->dp; /* * Set up environment. */ args = state->args; ASSERT(args != NULL); old_info = old_blk->bp->b_addr; new_info = new_blk->bp->b_addr; ASSERT(old_blk->magic == XFS_DA_NODE_MAGIC || old_blk->magic == XFS_DIR2_LEAFN_MAGIC || old_blk->magic == XFS_ATTR_LEAF_MAGIC); switch (old_blk->magic) { case XFS_ATTR_LEAF_MAGIC: before = xfs_attr_leaf_order(old_blk->bp, new_blk->bp); break; case XFS_DIR2_LEAFN_MAGIC: before = xfs_dir2_leafn_order(dp, old_blk->bp, new_blk->bp); break; case XFS_DA_NODE_MAGIC: before = xfs_da3_node_order(dp, old_blk->bp, new_blk->bp); break; } /* * Link blocks in appropriate order. */ if (before) { /* * Link new block in before existing block. */ trace_xfs_da_link_before(args); new_info->forw = cpu_to_be32(old_blk->blkno); new_info->back = old_info->back; if (old_info->back) { error = xfs_da3_node_read(args->trans, dp, be32_to_cpu(old_info->back), -1, &bp, args->whichfork); if (error) return error; ASSERT(bp != NULL); tmp_info = bp->b_addr; ASSERT(tmp_info->magic == old_info->magic); ASSERT(be32_to_cpu(tmp_info->forw) == old_blk->blkno); tmp_info->forw = cpu_to_be32(new_blk->blkno); xfs_trans_log_buf(args->trans, bp, 0, sizeof(*tmp_info)-1); } old_info->back = cpu_to_be32(new_blk->blkno); } else { /* * Link new block in after existing block. */ trace_xfs_da_link_after(args); new_info->forw = old_info->forw; new_info->back = cpu_to_be32(old_blk->blkno); if (old_info->forw) { error = xfs_da3_node_read(args->trans, dp, be32_to_cpu(old_info->forw), -1, &bp, args->whichfork); if (error) return error; ASSERT(bp != NULL); tmp_info = bp->b_addr; ASSERT(tmp_info->magic == old_info->magic); ASSERT(be32_to_cpu(tmp_info->back) == old_blk->blkno); tmp_info->back = cpu_to_be32(new_blk->blkno); xfs_trans_log_buf(args->trans, bp, 0, sizeof(*tmp_info)-1); } old_info->forw = cpu_to_be32(new_blk->blkno); } xfs_trans_log_buf(args->trans, old_blk->bp, 0, sizeof(*tmp_info) - 1); xfs_trans_log_buf(args->trans, new_blk->bp, 0, sizeof(*tmp_info) - 1); return 0; } /* * Unlink a block from a doubly linked list of blocks. */ STATIC int /* error */ xfs_da3_blk_unlink( struct xfs_da_state *state, struct xfs_da_state_blk *drop_blk, struct xfs_da_state_blk *save_blk) { struct xfs_da_blkinfo *drop_info; struct xfs_da_blkinfo *save_info; struct xfs_da_blkinfo *tmp_info; struct xfs_da_args *args; struct xfs_buf *bp; int error; /* * Set up environment. */ args = state->args; ASSERT(args != NULL); save_info = save_blk->bp->b_addr; drop_info = drop_blk->bp->b_addr; ASSERT(save_blk->magic == XFS_DA_NODE_MAGIC || save_blk->magic == XFS_DIR2_LEAFN_MAGIC || save_blk->magic == XFS_ATTR_LEAF_MAGIC); ASSERT(save_blk->magic == drop_blk->magic); ASSERT((be32_to_cpu(save_info->forw) == drop_blk->blkno) || (be32_to_cpu(save_info->back) == drop_blk->blkno)); ASSERT((be32_to_cpu(drop_info->forw) == save_blk->blkno) || (be32_to_cpu(drop_info->back) == save_blk->blkno)); /* * Unlink the leaf block from the doubly linked chain of leaves. */ if (be32_to_cpu(save_info->back) == drop_blk->blkno) { trace_xfs_da_unlink_back(args); save_info->back = drop_info->back; if (drop_info->back) { error = xfs_da3_node_read(args->trans, args->dp, be32_to_cpu(drop_info->back), -1, &bp, args->whichfork); if (error) return error; ASSERT(bp != NULL); tmp_info = bp->b_addr; ASSERT(tmp_info->magic == save_info->magic); ASSERT(be32_to_cpu(tmp_info->forw) == drop_blk->blkno); tmp_info->forw = cpu_to_be32(save_blk->blkno); xfs_trans_log_buf(args->trans, bp, 0, sizeof(*tmp_info) - 1); } } else { trace_xfs_da_unlink_forward(args); save_info->forw = drop_info->forw; if (drop_info->forw) { error = xfs_da3_node_read(args->trans, args->dp, be32_to_cpu(drop_info->forw), -1, &bp, args->whichfork); if (error) return error; ASSERT(bp != NULL); tmp_info = bp->b_addr; ASSERT(tmp_info->magic == save_info->magic); ASSERT(be32_to_cpu(tmp_info->back) == drop_blk->blkno); tmp_info->back = cpu_to_be32(save_blk->blkno); xfs_trans_log_buf(args->trans, bp, 0, sizeof(*tmp_info) - 1); } } xfs_trans_log_buf(args->trans, save_blk->bp, 0, sizeof(*save_info) - 1); return 0; } /* * Move a path "forward" or "!forward" one block at the current level. * * This routine will adjust a "path" to point to the next block * "forward" (higher hashvalues) or "!forward" (lower hashvals) in the * Btree, including updating pointers to the intermediate nodes between * the new bottom and the root. */ int /* error */ xfs_da3_path_shift( struct xfs_da_state *state, struct xfs_da_state_path *path, int forward, int release, int *result) { struct xfs_da_state_blk *blk; struct xfs_da_blkinfo *info; struct xfs_da_intnode *node; struct xfs_da_args *args; struct xfs_da_node_entry *btree; struct xfs_da3_icnode_hdr nodehdr; xfs_dablk_t blkno = 0; int level; int error; struct xfs_inode *dp = state->args->dp; trace_xfs_da_path_shift(state->args); /* * Roll up the Btree looking for the first block where our * current index is not at the edge of the block. Note that * we skip the bottom layer because we want the sibling block. */ args = state->args; ASSERT(args != NULL); ASSERT(path != NULL); ASSERT((path->active > 0) && (path->active < XFS_DA_NODE_MAXDEPTH)); level = (path->active-1) - 1; /* skip bottom layer in path */ for (blk = &path->blk[level]; level >= 0; blk--, level--) { node = blk->bp->b_addr; dp->d_ops->node_hdr_from_disk(&nodehdr, node); btree = dp->d_ops->node_tree_p(node); if (forward && (blk->index < nodehdr.count - 1)) { blk->index++; blkno = be32_to_cpu(btree[blk->index].before); break; } else if (!forward && (blk->index > 0)) { blk->index--; blkno = be32_to_cpu(btree[blk->index].before); break; } } if (level < 0) { *result = -ENOENT; /* we're out of our tree */ ASSERT(args->op_flags & XFS_DA_OP_OKNOENT); return 0; } /* * Roll down the edge of the subtree until we reach the * same depth we were at originally. */ for (blk++, level++; level < path->active; blk++, level++) { /* * Release the old block. * (if it's dirty, trans won't actually let go) */ if (release) xfs_trans_brelse(args->trans, blk->bp); /* * Read the next child block. */ blk->blkno = blkno; error = xfs_da3_node_read(args->trans, dp, blkno, -1, &blk->bp, args->whichfork); if (error) return error; info = blk->bp->b_addr; ASSERT(info->magic == cpu_to_be16(XFS_DA_NODE_MAGIC) || info->magic == cpu_to_be16(XFS_DA3_NODE_MAGIC) || info->magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC) || info->magic == cpu_to_be16(XFS_DIR3_LEAFN_MAGIC) || info->magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC) || info->magic == cpu_to_be16(XFS_ATTR3_LEAF_MAGIC)); /* * Note: we flatten the magic number to a single type so we * don't have to compare against crc/non-crc types elsewhere. */ switch (be16_to_cpu(info->magic)) { case XFS_DA_NODE_MAGIC: case XFS_DA3_NODE_MAGIC: blk->magic = XFS_DA_NODE_MAGIC; node = (xfs_da_intnode_t *)info; dp->d_ops->node_hdr_from_disk(&nodehdr, node); btree = dp->d_ops->node_tree_p(node); blk->hashval = be32_to_cpu(btree[nodehdr.count - 1].hashval); if (forward) blk->index = 0; else blk->index = nodehdr.count - 1; blkno = be32_to_cpu(btree[blk->index].before); break; case XFS_ATTR_LEAF_MAGIC: case XFS_ATTR3_LEAF_MAGIC: blk->magic = XFS_ATTR_LEAF_MAGIC; ASSERT(level == path->active-1); blk->index = 0; blk->hashval = xfs_attr_leaf_lasthash(blk->bp, NULL); break; case XFS_DIR2_LEAFN_MAGIC: case XFS_DIR3_LEAFN_MAGIC: blk->magic = XFS_DIR2_LEAFN_MAGIC; ASSERT(level == path->active-1); blk->index = 0; blk->hashval = xfs_dir2_leafn_lasthash(args->dp, blk->bp, NULL); break; default: ASSERT(0); break; } } *result = 0; return 0; } /*======================================================================== * Utility routines. *========================================================================*/ /* * Implement a simple hash on a character string. * Rotate the hash value by 7 bits, then XOR each character in. * This is implemented with some source-level loop unrolling. */ xfs_dahash_t xfs_da_hashname(const __uint8_t *name, int namelen) { xfs_dahash_t hash; /* * Do four characters at a time as long as we can. */ for (hash = 0; namelen >= 4; namelen -= 4, name += 4) hash = (name[0] << 21) ^ (name[1] << 14) ^ (name[2] << 7) ^ (name[3] << 0) ^ rol32(hash, 7 * 4); /* * Now do the rest of the characters. */ switch (namelen) { case 3: return (name[0] << 14) ^ (name[1] << 7) ^ (name[2] << 0) ^ rol32(hash, 7 * 3); case 2: return (name[0] << 7) ^ (name[1] << 0) ^ rol32(hash, 7 * 2); case 1: return (name[0] << 0) ^ rol32(hash, 7 * 1); default: /* case 0: */ return hash; } } enum xfs_dacmp xfs_da_compname( struct xfs_da_args *args, const unsigned char *name, int len) { return (args->namelen == len && memcmp(args->name, name, len) == 0) ? XFS_CMP_EXACT : XFS_CMP_DIFFERENT; } static xfs_dahash_t xfs_default_hashname( struct xfs_name *name) { return xfs_da_hashname(name->name, name->len); } const struct xfs_nameops xfs_default_nameops = { .hashname = xfs_default_hashname, .compname = xfs_da_compname }; int xfs_da_grow_inode_int( struct xfs_da_args *args, xfs_fileoff_t *bno, int count) { struct xfs_trans *tp = args->trans; struct xfs_inode *dp = args->dp; int w = args->whichfork; xfs_rfsblock_t nblks = dp->i_d.di_nblocks; struct xfs_bmbt_irec map, *mapp; int nmap, error, got, i, mapi; /* * Find a spot in the file space to put the new block. */ error = xfs_bmap_first_unused(tp, dp, count, bno, w); if (error) return error; /* * Try mapping it in one filesystem block. */ nmap = 1; ASSERT(args->firstblock != NULL); error = xfs_bmapi_write(tp, dp, *bno, count, xfs_bmapi_aflag(w)|XFS_BMAPI_METADATA|XFS_BMAPI_CONTIG, args->firstblock, args->total, &map, &nmap, args->flist); if (error) return error; ASSERT(nmap <= 1); if (nmap == 1) { mapp = ↦ mapi = 1; } else if (nmap == 0 && count > 1) { xfs_fileoff_t b; int c; /* * If we didn't get it and the block might work if fragmented, * try without the CONTIG flag. Loop until we get it all. */ mapp = kmem_alloc(sizeof(*mapp) * count, KM_SLEEP); for (b = *bno, mapi = 0; b < *bno + count; ) { nmap = MIN(XFS_BMAP_MAX_NMAP, count); c = (int)(*bno + count - b); error = xfs_bmapi_write(tp, dp, b, c, xfs_bmapi_aflag(w)|XFS_BMAPI_METADATA, args->firstblock, args->total, &mapp[mapi], &nmap, args->flist); if (error) goto out_free_map; if (nmap < 1) break; mapi += nmap; b = mapp[mapi - 1].br_startoff + mapp[mapi - 1].br_blockcount; } } else { mapi = 0; mapp = NULL; } /* * Count the blocks we got, make sure it matches the total. */ for (i = 0, got = 0; i < mapi; i++) got += mapp[i].br_blockcount; if (got != count || mapp[0].br_startoff != *bno || mapp[mapi - 1].br_startoff + mapp[mapi - 1].br_blockcount != *bno + count) { error = -ENOSPC; goto out_free_map; } /* account for newly allocated blocks in reserved blocks total */ args->total -= dp->i_d.di_nblocks - nblks; out_free_map: if (mapp != &map) kmem_free(mapp); return error; } /* * Add a block to the btree ahead of the file. * Return the new block number to the caller. */ int xfs_da_grow_inode( struct xfs_da_args *args, xfs_dablk_t *new_blkno) { xfs_fileoff_t bno; int error; trace_xfs_da_grow_inode(args); bno = args->geo->leafblk; error = xfs_da_grow_inode_int(args, &bno, args->geo->fsbcount); if (!error) *new_blkno = (xfs_dablk_t)bno; return error; } /* * Ick. We need to always be able to remove a btree block, even * if there's no space reservation because the filesystem is full. * This is called if xfs_bunmapi on a btree block fails due to ENOSPC. * It swaps the target block with the last block in the file. The * last block in the file can always be removed since it can't cause * a bmap btree split to do that. */ STATIC int xfs_da3_swap_lastblock( struct xfs_da_args *args, xfs_dablk_t *dead_blknop, struct xfs_buf **dead_bufp) { struct xfs_da_blkinfo *dead_info; struct xfs_da_blkinfo *sib_info; struct xfs_da_intnode *par_node; struct xfs_da_intnode *dead_node; struct xfs_dir2_leaf *dead_leaf2; struct xfs_da_node_entry *btree; struct xfs_da3_icnode_hdr par_hdr; struct xfs_inode *dp; struct xfs_trans *tp; struct xfs_mount *mp; struct xfs_buf *dead_buf; struct xfs_buf *last_buf; struct xfs_buf *sib_buf; struct xfs_buf *par_buf; xfs_dahash_t dead_hash; xfs_fileoff_t lastoff; xfs_dablk_t dead_blkno; xfs_dablk_t last_blkno; xfs_dablk_t sib_blkno; xfs_dablk_t par_blkno; int error; int w; int entno; int level; int dead_level; trace_xfs_da_swap_lastblock(args); dead_buf = *dead_bufp; dead_blkno = *dead_blknop; tp = args->trans; dp = args->dp; w = args->whichfork; ASSERT(w == XFS_DATA_FORK); mp = dp->i_mount; lastoff = args->geo->freeblk; error = xfs_bmap_last_before(tp, dp, &lastoff, w); if (error) return error; if (unlikely(lastoff == 0)) { XFS_ERROR_REPORT("xfs_da_swap_lastblock(1)", XFS_ERRLEVEL_LOW, mp); return -EFSCORRUPTED; } /* * Read the last block in the btree space. */ last_blkno = (xfs_dablk_t)lastoff - args->geo->fsbcount; error = xfs_da3_node_read(tp, dp, last_blkno, -1, &last_buf, w); if (error) return error; /* * Copy the last block into the dead buffer and log it. */ memcpy(dead_buf->b_addr, last_buf->b_addr, args->geo->blksize); xfs_trans_log_buf(tp, dead_buf, 0, args->geo->blksize - 1); dead_info = dead_buf->b_addr; /* * Get values from the moved block. */ if (dead_info->magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC) || dead_info->magic == cpu_to_be16(XFS_DIR3_LEAFN_MAGIC)) { struct xfs_dir3_icleaf_hdr leafhdr; struct xfs_dir2_leaf_entry *ents; dead_leaf2 = (xfs_dir2_leaf_t *)dead_info; dp->d_ops->leaf_hdr_from_disk(&leafhdr, dead_leaf2); ents = dp->d_ops->leaf_ents_p(dead_leaf2); dead_level = 0; dead_hash = be32_to_cpu(ents[leafhdr.count - 1].hashval); } else { struct xfs_da3_icnode_hdr deadhdr; dead_node = (xfs_da_intnode_t *)dead_info; dp->d_ops->node_hdr_from_disk(&deadhdr, dead_node); btree = dp->d_ops->node_tree_p(dead_node); dead_level = deadhdr.level; dead_hash = be32_to_cpu(btree[deadhdr.count - 1].hashval); } sib_buf = par_buf = NULL; /* * If the moved block has a left sibling, fix up the pointers. */ if ((sib_blkno = be32_to_cpu(dead_info->back))) { error = xfs_da3_node_read(tp, dp, sib_blkno, -1, &sib_buf, w); if (error) goto done; sib_info = sib_buf->b_addr; if (unlikely( be32_to_cpu(sib_info->forw) != last_blkno || sib_info->magic != dead_info->magic)) { XFS_ERROR_REPORT("xfs_da_swap_lastblock(2)", XFS_ERRLEVEL_LOW, mp); error = -EFSCORRUPTED; goto done; } sib_info->forw = cpu_to_be32(dead_blkno); xfs_trans_log_buf(tp, sib_buf, XFS_DA_LOGRANGE(sib_info, &sib_info->forw, sizeof(sib_info->forw))); sib_buf = NULL; } /* * If the moved block has a right sibling, fix up the pointers. */ if ((sib_blkno = be32_to_cpu(dead_info->forw))) { error = xfs_da3_node_read(tp, dp, sib_blkno, -1, &sib_buf, w); if (error) goto done; sib_info = sib_buf->b_addr; if (unlikely( be32_to_cpu(sib_info->back) != last_blkno || sib_info->magic != dead_info->magic)) { XFS_ERROR_REPORT("xfs_da_swap_lastblock(3)", XFS_ERRLEVEL_LOW, mp); error = -EFSCORRUPTED; goto done; } sib_info->back = cpu_to_be32(dead_blkno); xfs_trans_log_buf(tp, sib_buf, XFS_DA_LOGRANGE(sib_info, &sib_info->back, sizeof(sib_info->back))); sib_buf = NULL; } par_blkno = args->geo->leafblk; level = -1; /* * Walk down the tree looking for the parent of the moved block. */ for (;;) { error = xfs_da3_node_read(tp, dp, par_blkno, -1, &par_buf, w); if (error) goto done; par_node = par_buf->b_addr; dp->d_ops->node_hdr_from_disk(&par_hdr, par_node); if (level >= 0 && level != par_hdr.level + 1) { XFS_ERROR_REPORT("xfs_da_swap_lastblock(4)", XFS_ERRLEVEL_LOW, mp); error = -EFSCORRUPTED; goto done; } level = par_hdr.level; btree = dp->d_ops->node_tree_p(par_node); for (entno = 0; entno < par_hdr.count && be32_to_cpu(btree[entno].hashval) < dead_hash; entno++) continue; if (entno == par_hdr.count) { XFS_ERROR_REPORT("xfs_da_swap_lastblock(5)", XFS_ERRLEVEL_LOW, mp); error = -EFSCORRUPTED; goto done; } par_blkno = be32_to_cpu(btree[entno].before); if (level == dead_level + 1) break; xfs_trans_brelse(tp, par_buf); par_buf = NULL; } /* * We're in the right parent block. * Look for the right entry. */ for (;;) { for (; entno < par_hdr.count && be32_to_cpu(btree[entno].before) != last_blkno; entno++) continue; if (entno < par_hdr.count) break; par_blkno = par_hdr.forw; xfs_trans_brelse(tp, par_buf); par_buf = NULL; if (unlikely(par_blkno == 0)) { XFS_ERROR_REPORT("xfs_da_swap_lastblock(6)", XFS_ERRLEVEL_LOW, mp); error = -EFSCORRUPTED; goto done; } error = xfs_da3_node_read(tp, dp, par_blkno, -1, &par_buf, w); if (error) goto done; par_node = par_buf->b_addr; dp->d_ops->node_hdr_from_disk(&par_hdr, par_node); if (par_hdr.level != level) { XFS_ERROR_REPORT("xfs_da_swap_lastblock(7)", XFS_ERRLEVEL_LOW, mp); error = -EFSCORRUPTED; goto done; } btree = dp->d_ops->node_tree_p(par_node); entno = 0; } /* * Update the parent entry pointing to the moved block. */ btree[entno].before = cpu_to_be32(dead_blkno); xfs_trans_log_buf(tp, par_buf, XFS_DA_LOGRANGE(par_node, &btree[entno].before, sizeof(btree[entno].before))); *dead_blknop = last_blkno; *dead_bufp = last_buf; return 0; done: if (par_buf) xfs_trans_brelse(tp, par_buf); if (sib_buf) xfs_trans_brelse(tp, sib_buf); xfs_trans_brelse(tp, last_buf); return error; } /* * Remove a btree block from a directory or attribute. */ int xfs_da_shrink_inode( xfs_da_args_t *args, xfs_dablk_t dead_blkno, struct xfs_buf *dead_buf) { xfs_inode_t *dp; int done, error, w, count; xfs_trans_t *tp; trace_xfs_da_shrink_inode(args); dp = args->dp; w = args->whichfork; tp = args->trans; count = args->geo->fsbcount; for (;;) { /* * Remove extents. If we get ENOSPC for a dir we have to move * the last block to the place we want to kill. */ error = xfs_bunmapi(tp, dp, dead_blkno, count, xfs_bmapi_aflag(w), 0, args->firstblock, args->flist, &done); if (error == -ENOSPC) { if (w != XFS_DATA_FORK) break; error = xfs_da3_swap_lastblock(args, &dead_blkno, &dead_buf); if (error) break; } else { break; } } xfs_trans_binval(tp, dead_buf); return error; } /* * See if the mapping(s) for this btree block are valid, i.e. * don't contain holes, are logically contiguous, and cover the whole range. */ STATIC int xfs_da_map_covers_blocks( int nmap, xfs_bmbt_irec_t *mapp, xfs_dablk_t bno, int count) { int i; xfs_fileoff_t off; for (i = 0, off = bno; i < nmap; i++) { if (mapp[i].br_startblock == HOLESTARTBLOCK || mapp[i].br_startblock == DELAYSTARTBLOCK) { return 0; } if (off != mapp[i].br_startoff) { return 0; } off += mapp[i].br_blockcount; } return off == bno + count; } /* * Convert a struct xfs_bmbt_irec to a struct xfs_buf_map. * * For the single map case, it is assumed that the caller has provided a pointer * to a valid xfs_buf_map. For the multiple map case, this function will * allocate the xfs_buf_map to hold all the maps and replace the caller's single * map pointer with the allocated map. */ static int xfs_buf_map_from_irec( struct xfs_mount *mp, struct xfs_buf_map **mapp, int *nmaps, struct xfs_bmbt_irec *irecs, int nirecs) { struct xfs_buf_map *map; int i; ASSERT(*nmaps == 1); ASSERT(nirecs >= 1); if (nirecs > 1) { map = kmem_zalloc(nirecs * sizeof(struct xfs_buf_map), KM_SLEEP | KM_NOFS); if (!map) return -ENOMEM; *mapp = map; } *nmaps = nirecs; map = *mapp; for (i = 0; i < *nmaps; i++) { ASSERT(irecs[i].br_startblock != DELAYSTARTBLOCK && irecs[i].br_startblock != HOLESTARTBLOCK); map[i].bm_bn = XFS_FSB_TO_DADDR(mp, irecs[i].br_startblock); map[i].bm_len = XFS_FSB_TO_BB(mp, irecs[i].br_blockcount); } return 0; } /* * Map the block we are given ready for reading. There are three possible return * values: * -1 - will be returned if we land in a hole and mappedbno == -2 so the * caller knows not to execute a subsequent read. * 0 - if we mapped the block successfully * >0 - positive error number if there was an error. */ static int xfs_dabuf_map( struct xfs_inode *dp, xfs_dablk_t bno, xfs_daddr_t mappedbno, int whichfork, struct xfs_buf_map **map, int *nmaps) { struct xfs_mount *mp = dp->i_mount; int nfsb; int error = 0; struct xfs_bmbt_irec irec; struct xfs_bmbt_irec *irecs = &irec; int nirecs; ASSERT(map && *map); ASSERT(*nmaps == 1); if (whichfork == XFS_DATA_FORK) nfsb = mp->m_dir_geo->fsbcount; else nfsb = mp->m_attr_geo->fsbcount; /* * Caller doesn't have a mapping. -2 means don't complain * if we land in a hole. */ if (mappedbno == -1 || mappedbno == -2) { /* * Optimize the one-block case. */ if (nfsb != 1) irecs = kmem_zalloc(sizeof(irec) * nfsb, KM_SLEEP | KM_NOFS); nirecs = nfsb; error = xfs_bmapi_read(dp, (xfs_fileoff_t)bno, nfsb, irecs, &nirecs, xfs_bmapi_aflag(whichfork)); if (error) goto out; } else { irecs->br_startblock = XFS_DADDR_TO_FSB(mp, mappedbno); irecs->br_startoff = (xfs_fileoff_t)bno; irecs->br_blockcount = nfsb; irecs->br_state = 0; nirecs = 1; } if (!xfs_da_map_covers_blocks(nirecs, irecs, bno, nfsb)) { error = mappedbno == -2 ? -1 : -EFSCORRUPTED; if (unlikely(error == -EFSCORRUPTED)) { if (xfs_error_level >= XFS_ERRLEVEL_LOW) { int i; xfs_alert(mp, "%s: bno %lld dir: inode %lld", __func__, (long long)bno, (long long)dp->i_ino); for (i = 0; i < *nmaps; i++) { xfs_alert(mp, "[%02d] br_startoff %lld br_startblock %lld br_blockcount %lld br_state %d", i, (long long)irecs[i].br_startoff, (long long)irecs[i].br_startblock, (long long)irecs[i].br_blockcount, irecs[i].br_state); } } XFS_ERROR_REPORT("xfs_da_do_buf(1)", XFS_ERRLEVEL_LOW, mp); } goto out; } error = xfs_buf_map_from_irec(mp, map, nmaps, irecs, nirecs); out: if (irecs != &irec) kmem_free(irecs); return error; } /* * Get a buffer for the dir/attr block. */ int xfs_da_get_buf( struct xfs_trans *trans, struct xfs_inode *dp, xfs_dablk_t bno, xfs_daddr_t mappedbno, struct xfs_buf **bpp, int whichfork) { struct xfs_buf *bp; struct xfs_buf_map map; struct xfs_buf_map *mapp; int nmap; int error; *bpp = NULL; mapp = ↦ nmap = 1; error = xfs_dabuf_map(dp, bno, mappedbno, whichfork, &mapp, &nmap); if (error) { /* mapping a hole is not an error, but we don't continue */ if (error == -1) error = 0; goto out_free; } bp = xfs_trans_get_buf_map(trans, dp->i_mount->m_ddev_targp, mapp, nmap, 0); error = bp ? bp->b_error : -EIO; if (error) { if (bp) xfs_trans_brelse(trans, bp); goto out_free; } *bpp = bp; out_free: if (mapp != &map) kmem_free(mapp); return error; } /* * Get a buffer for the dir/attr block, fill in the contents. */ int xfs_da_read_buf( struct xfs_trans *trans, struct xfs_inode *dp, xfs_dablk_t bno, xfs_daddr_t mappedbno, struct xfs_buf **bpp, int whichfork, const struct xfs_buf_ops *ops) { struct xfs_buf *bp; struct xfs_buf_map map; struct xfs_buf_map *mapp; int nmap; int error; *bpp = NULL; mapp = ↦ nmap = 1; error = xfs_dabuf_map(dp, bno, mappedbno, whichfork, &mapp, &nmap); if (error) { /* mapping a hole is not an error, but we don't continue */ if (error == -1) error = 0; goto out_free; } error = xfs_trans_read_buf_map(dp->i_mount, trans, dp->i_mount->m_ddev_targp, mapp, nmap, 0, &bp, ops); if (error) goto out_free; if (whichfork == XFS_ATTR_FORK) xfs_buf_set_ref(bp, XFS_ATTR_BTREE_REF); else xfs_buf_set_ref(bp, XFS_DIR_BTREE_REF); *bpp = bp; out_free: if (mapp != &map) kmem_free(mapp); return error; } /* * Readahead the dir/attr block. */ xfs_daddr_t xfs_da_reada_buf( struct xfs_inode *dp, xfs_dablk_t bno, xfs_daddr_t mappedbno, int whichfork, const struct xfs_buf_ops *ops) { struct xfs_buf_map map; struct xfs_buf_map *mapp; int nmap; int error; mapp = ↦ nmap = 1; error = xfs_dabuf_map(dp, bno, mappedbno, whichfork, &mapp, &nmap); if (error) { /* mapping a hole is not an error, but we don't continue */ if (error == -1) error = 0; goto out_free; } mappedbno = mapp[0].bm_bn; xfs_buf_readahead_map(dp->i_mount->m_ddev_targp, mapp, nmap, ops); out_free: if (mapp != &map) kmem_free(mapp); if (error) return -1; return mappedbno; } partclone-0.2.86/src/xfs/xfs_da_btree.h000066400000000000000000000203321262102574200177640ustar00rootroot00000000000000/* * Copyright (c) 2000,2002,2005 Silicon Graphics, Inc. * Copyright (c) 2013 Red Hat, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __XFS_DA_BTREE_H__ #define __XFS_DA_BTREE_H__ struct xfs_bmap_free; struct xfs_inode; struct xfs_trans; struct zone; struct xfs_dir_ops; /* * Directory/attribute geometry information. There will be one of these for each * data fork type, and it will be passed around via the xfs_da_args. Global * structures will be attached to the xfs_mount. */ struct xfs_da_geometry { int blksize; /* da block size in bytes */ int fsbcount; /* da block size in filesystem blocks */ uint8_t fsblog; /* log2 of _filesystem_ block size */ uint8_t blklog; /* log2 of da block size */ uint node_ents; /* # of entries in a danode */ int magicpct; /* 37% of block size in bytes */ xfs_dablk_t datablk; /* blockno of dir data v2 */ xfs_dablk_t leafblk; /* blockno of leaf data v2 */ xfs_dablk_t freeblk; /* blockno of free data v2 */ }; /*======================================================================== * Btree searching and modification structure definitions. *========================================================================*/ /* * Search comparison results */ enum xfs_dacmp { XFS_CMP_DIFFERENT, /* names are completely different */ XFS_CMP_EXACT, /* names are exactly the same */ XFS_CMP_CASE /* names are same but differ in case */ }; /* * Structure to ease passing around component names. */ typedef struct xfs_da_args { struct xfs_da_geometry *geo; /* da block geometry */ const __uint8_t *name; /* string (maybe not NULL terminated) */ int namelen; /* length of string (maybe no NULL) */ __uint8_t filetype; /* filetype of inode for directories */ __uint8_t *value; /* set of bytes (maybe contain NULLs) */ int valuelen; /* length of value */ int flags; /* argument flags (eg: ATTR_NOCREATE) */ xfs_dahash_t hashval; /* hash value of name */ xfs_ino_t inumber; /* input/output inode number */ struct xfs_inode *dp; /* directory inode to manipulate */ xfs_fsblock_t *firstblock; /* ptr to firstblock for bmap calls */ struct xfs_bmap_free *flist; /* ptr to freelist for bmap_finish */ struct xfs_trans *trans; /* current trans (changes over time) */ xfs_extlen_t total; /* total blocks needed, for 1st bmap */ int whichfork; /* data or attribute fork */ xfs_dablk_t blkno; /* blkno of attr leaf of interest */ int index; /* index of attr of interest in blk */ xfs_dablk_t rmtblkno; /* remote attr value starting blkno */ int rmtblkcnt; /* remote attr value block count */ int rmtvaluelen; /* remote attr value length in bytes */ xfs_dablk_t blkno2; /* blkno of 2nd attr leaf of interest */ int index2; /* index of 2nd attr in blk */ xfs_dablk_t rmtblkno2; /* remote attr value starting blkno */ int rmtblkcnt2; /* remote attr value block count */ int rmtvaluelen2; /* remote attr value length in bytes */ int op_flags; /* operation flags */ enum xfs_dacmp cmpresult; /* name compare result for lookups */ } xfs_da_args_t; /* * Operation flags: */ #define XFS_DA_OP_JUSTCHECK 0x0001 /* check for ok with no space */ #define XFS_DA_OP_RENAME 0x0002 /* this is an atomic rename op */ #define XFS_DA_OP_ADDNAME 0x0004 /* this is an add operation */ #define XFS_DA_OP_OKNOENT 0x0008 /* lookup/add op, ENOENT ok, else die */ #define XFS_DA_OP_CILOOKUP 0x0010 /* lookup to return CI name if found */ #define XFS_DA_OP_FLAGS \ { XFS_DA_OP_JUSTCHECK, "JUSTCHECK" }, \ { XFS_DA_OP_RENAME, "RENAME" }, \ { XFS_DA_OP_ADDNAME, "ADDNAME" }, \ { XFS_DA_OP_OKNOENT, "OKNOENT" }, \ { XFS_DA_OP_CILOOKUP, "CILOOKUP" } /* * Storage for holding state during Btree searches and split/join ops. * * Only need space for 5 intermediate nodes. With a minimum of 62-way * fanout to the Btree, we can support over 900 million directory blocks, * which is slightly more than enough. */ typedef struct xfs_da_state_blk { struct xfs_buf *bp; /* buffer containing block */ xfs_dablk_t blkno; /* filesystem blkno of buffer */ xfs_daddr_t disk_blkno; /* on-disk blkno (in BBs) of buffer */ int index; /* relevant index into block */ xfs_dahash_t hashval; /* last hash value in block */ int magic; /* blk's magic number, ie: blk type */ } xfs_da_state_blk_t; typedef struct xfs_da_state_path { int active; /* number of active levels */ xfs_da_state_blk_t blk[XFS_DA_NODE_MAXDEPTH]; } xfs_da_state_path_t; typedef struct xfs_da_state { xfs_da_args_t *args; /* filename arguments */ struct xfs_mount *mp; /* filesystem mount point */ xfs_da_state_path_t path; /* search/split paths */ xfs_da_state_path_t altpath; /* alternate path for join */ unsigned char inleaf; /* insert into 1->lf, 0->splf */ unsigned char extravalid; /* T/F: extrablk is in use */ unsigned char extraafter; /* T/F: extrablk is after new */ xfs_da_state_blk_t extrablk; /* for double-splits on leaves */ /* for dirv2 extrablk is data */ } xfs_da_state_t; /* * Utility macros to aid in logging changed structure fields. */ #define XFS_DA_LOGOFF(BASE, ADDR) ((char *)(ADDR) - (char *)(BASE)) #define XFS_DA_LOGRANGE(BASE, ADDR, SIZE) \ (uint)(XFS_DA_LOGOFF(BASE, ADDR)), \ (uint)(XFS_DA_LOGOFF(BASE, ADDR)+(SIZE)-1) /* * Name ops for directory and/or attr name operations */ struct xfs_nameops { xfs_dahash_t (*hashname)(struct xfs_name *); enum xfs_dacmp (*compname)(struct xfs_da_args *, const unsigned char *, int); }; /*======================================================================== * Function prototypes. *========================================================================*/ /* * Routines used for growing the Btree. */ int xfs_da3_node_create(struct xfs_da_args *args, xfs_dablk_t blkno, int level, struct xfs_buf **bpp, int whichfork); int xfs_da3_split(xfs_da_state_t *state); /* * Routines used for shrinking the Btree. */ int xfs_da3_join(xfs_da_state_t *state); void xfs_da3_fixhashpath(struct xfs_da_state *state, struct xfs_da_state_path *path_to_to_fix); /* * Routines used for finding things in the Btree. */ int xfs_da3_node_lookup_int(xfs_da_state_t *state, int *result); int xfs_da3_path_shift(xfs_da_state_t *state, xfs_da_state_path_t *path, int forward, int release, int *result); /* * Utility routines. */ int xfs_da3_blk_link(xfs_da_state_t *state, xfs_da_state_blk_t *old_blk, xfs_da_state_blk_t *new_blk); int xfs_da3_node_read(struct xfs_trans *tp, struct xfs_inode *dp, xfs_dablk_t bno, xfs_daddr_t mappedbno, struct xfs_buf **bpp, int which_fork); /* * Utility routines. */ int xfs_da_grow_inode(xfs_da_args_t *args, xfs_dablk_t *new_blkno); int xfs_da_grow_inode_int(struct xfs_da_args *args, xfs_fileoff_t *bno, int count); int xfs_da_get_buf(struct xfs_trans *trans, struct xfs_inode *dp, xfs_dablk_t bno, xfs_daddr_t mappedbno, struct xfs_buf **bp, int whichfork); int xfs_da_read_buf(struct xfs_trans *trans, struct xfs_inode *dp, xfs_dablk_t bno, xfs_daddr_t mappedbno, struct xfs_buf **bpp, int whichfork, const struct xfs_buf_ops *ops); xfs_daddr_t xfs_da_reada_buf(struct xfs_inode *dp, xfs_dablk_t bno, xfs_daddr_t mapped_bno, int whichfork, const struct xfs_buf_ops *ops); int xfs_da_shrink_inode(xfs_da_args_t *args, xfs_dablk_t dead_blkno, struct xfs_buf *dead_buf); uint xfs_da_hashname(const __uint8_t *name_string, int name_length); enum xfs_dacmp xfs_da_compname(struct xfs_da_args *args, const unsigned char *name, int len); xfs_da_state_t *xfs_da_state_alloc(void); void xfs_da_state_free(xfs_da_state_t *state); extern struct kmem_zone *xfs_da_state_zone; extern const struct xfs_nameops xfs_default_nameops; #endif /* __XFS_DA_BTREE_H__ */ partclone-0.2.86/src/xfs/xfs_da_format.c000066400000000000000000000600611262102574200201510ustar00rootroot00000000000000/* * Copyright (c) 2000,2002,2005 Silicon Graphics, Inc. * Copyright (c) 2013 Red Hat, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_mount.h" #include "xfs_da_format.h" #include "xfs_da_btree.h" #include "xfs_inode.h" #include "xfs_dir2.h" #include "xfs_dir2_priv.h" /* * Shortform directory ops */ static int xfs_dir2_sf_entsize( struct xfs_dir2_sf_hdr *hdr, int len) { int count = sizeof(struct xfs_dir2_sf_entry); /* namelen + offset */ count += len; /* name */ count += hdr->i8count ? sizeof(xfs_dir2_ino8_t) : sizeof(xfs_dir2_ino4_t); /* ino # */ return count; } static int xfs_dir3_sf_entsize( struct xfs_dir2_sf_hdr *hdr, int len) { return xfs_dir2_sf_entsize(hdr, len) + sizeof(__uint8_t); } static struct xfs_dir2_sf_entry * xfs_dir2_sf_nextentry( struct xfs_dir2_sf_hdr *hdr, struct xfs_dir2_sf_entry *sfep) { return (struct xfs_dir2_sf_entry *) ((char *)sfep + xfs_dir2_sf_entsize(hdr, sfep->namelen)); } static struct xfs_dir2_sf_entry * xfs_dir3_sf_nextentry( struct xfs_dir2_sf_hdr *hdr, struct xfs_dir2_sf_entry *sfep) { return (struct xfs_dir2_sf_entry *) ((char *)sfep + xfs_dir3_sf_entsize(hdr, sfep->namelen)); } /* * For filetype enabled shortform directories, the file type field is stored at * the end of the name. Because it's only a single byte, endian conversion is * not necessary. For non-filetype enable directories, the type is always * unknown and we never store the value. */ static __uint8_t xfs_dir2_sfe_get_ftype( struct xfs_dir2_sf_entry *sfep) { return XFS_DIR3_FT_UNKNOWN; } static void xfs_dir2_sfe_put_ftype( struct xfs_dir2_sf_entry *sfep, __uint8_t ftype) { ASSERT(ftype < XFS_DIR3_FT_MAX); } static __uint8_t xfs_dir3_sfe_get_ftype( struct xfs_dir2_sf_entry *sfep) { __uint8_t ftype; ftype = sfep->name[sfep->namelen]; if (ftype >= XFS_DIR3_FT_MAX) return XFS_DIR3_FT_UNKNOWN; return ftype; } static void xfs_dir3_sfe_put_ftype( struct xfs_dir2_sf_entry *sfep, __uint8_t ftype) { ASSERT(ftype < XFS_DIR3_FT_MAX); sfep->name[sfep->namelen] = ftype; } /* * Inode numbers in short-form directories can come in two versions, * either 4 bytes or 8 bytes wide. These helpers deal with the * two forms transparently by looking at the headers i8count field. * * For 64-bit inode number the most significant byte must be zero. */ static xfs_ino_t xfs_dir2_sf_get_ino( struct xfs_dir2_sf_hdr *hdr, xfs_dir2_inou_t *from) { if (hdr->i8count) return get_unaligned_be64(&from->i8.i) & 0x00ffffffffffffffULL; else return get_unaligned_be32(&from->i4.i); } static void xfs_dir2_sf_put_ino( struct xfs_dir2_sf_hdr *hdr, xfs_dir2_inou_t *to, xfs_ino_t ino) { ASSERT((ino & 0xff00000000000000ULL) == 0); if (hdr->i8count) put_unaligned_be64(ino, &to->i8.i); else put_unaligned_be32(ino, &to->i4.i); } static xfs_ino_t xfs_dir2_sf_get_parent_ino( struct xfs_dir2_sf_hdr *hdr) { return xfs_dir2_sf_get_ino(hdr, &hdr->parent); } static void xfs_dir2_sf_put_parent_ino( struct xfs_dir2_sf_hdr *hdr, xfs_ino_t ino) { xfs_dir2_sf_put_ino(hdr, &hdr->parent, ino); } /* * In short-form directory entries the inode numbers are stored at variable * offset behind the entry name. If the entry stores a filetype value, then it * sits between the name and the inode number. Hence the inode numbers may only * be accessed through the helpers below. */ static xfs_ino_t xfs_dir2_sfe_get_ino( struct xfs_dir2_sf_hdr *hdr, struct xfs_dir2_sf_entry *sfep) { return xfs_dir2_sf_get_ino(hdr, (xfs_dir2_inou_t *)&sfep->name[sfep->namelen]); } static void xfs_dir2_sfe_put_ino( struct xfs_dir2_sf_hdr *hdr, struct xfs_dir2_sf_entry *sfep, xfs_ino_t ino) { xfs_dir2_sf_put_ino(hdr, (xfs_dir2_inou_t *)&sfep->name[sfep->namelen], ino); } static xfs_ino_t xfs_dir3_sfe_get_ino( struct xfs_dir2_sf_hdr *hdr, struct xfs_dir2_sf_entry *sfep) { return xfs_dir2_sf_get_ino(hdr, (xfs_dir2_inou_t *)&sfep->name[sfep->namelen + 1]); } static void xfs_dir3_sfe_put_ino( struct xfs_dir2_sf_hdr *hdr, struct xfs_dir2_sf_entry *sfep, xfs_ino_t ino) { xfs_dir2_sf_put_ino(hdr, (xfs_dir2_inou_t *)&sfep->name[sfep->namelen + 1], ino); } /* * Directory data block operations */ /* * For special situations, the dirent size ends up fixed because we always know * what the size of the entry is. That's true for the "." and "..", and * therefore we know that they are a fixed size and hence their offsets are * constant, as is the first entry. * * Hence, this calculation is written as a macro to be able to be calculated at * compile time and so certain offsets can be calculated directly in the * structure initaliser via the macro. There are two macros - one for dirents * with ftype and without so there are no unresolvable conditionals in the * calculations. We also use round_up() as XFS_DIR2_DATA_ALIGN is always a power * of 2 and the compiler doesn't reject it (unlike roundup()). */ #define XFS_DIR2_DATA_ENTSIZE(n) \ round_up((offsetof(struct xfs_dir2_data_entry, name[0]) + (n) + \ sizeof(xfs_dir2_data_off_t)), XFS_DIR2_DATA_ALIGN) #define XFS_DIR3_DATA_ENTSIZE(n) \ round_up((offsetof(struct xfs_dir2_data_entry, name[0]) + (n) + \ sizeof(xfs_dir2_data_off_t) + sizeof(__uint8_t)), \ XFS_DIR2_DATA_ALIGN) static int xfs_dir2_data_entsize( int n) { return XFS_DIR2_DATA_ENTSIZE(n); } static int xfs_dir3_data_entsize( int n) { return XFS_DIR3_DATA_ENTSIZE(n); } static __uint8_t xfs_dir2_data_get_ftype( struct xfs_dir2_data_entry *dep) { return XFS_DIR3_FT_UNKNOWN; } static void xfs_dir2_data_put_ftype( struct xfs_dir2_data_entry *dep, __uint8_t ftype) { ASSERT(ftype < XFS_DIR3_FT_MAX); } static __uint8_t xfs_dir3_data_get_ftype( struct xfs_dir2_data_entry *dep) { __uint8_t ftype = dep->name[dep->namelen]; if (ftype >= XFS_DIR3_FT_MAX) return XFS_DIR3_FT_UNKNOWN; return ftype; } static void xfs_dir3_data_put_ftype( struct xfs_dir2_data_entry *dep, __uint8_t type) { ASSERT(type < XFS_DIR3_FT_MAX); ASSERT(dep->namelen != 0); dep->name[dep->namelen] = type; } /* * Pointer to an entry's tag word. */ static __be16 * xfs_dir2_data_entry_tag_p( struct xfs_dir2_data_entry *dep) { return (__be16 *)((char *)dep + xfs_dir2_data_entsize(dep->namelen) - sizeof(__be16)); } static __be16 * xfs_dir3_data_entry_tag_p( struct xfs_dir2_data_entry *dep) { return (__be16 *)((char *)dep + xfs_dir3_data_entsize(dep->namelen) - sizeof(__be16)); } /* * location of . and .. in data space (always block 0) */ static struct xfs_dir2_data_entry * xfs_dir2_data_dot_entry_p( struct xfs_dir2_data_hdr *hdr) { return (struct xfs_dir2_data_entry *) ((char *)hdr + sizeof(struct xfs_dir2_data_hdr)); } static struct xfs_dir2_data_entry * xfs_dir2_data_dotdot_entry_p( struct xfs_dir2_data_hdr *hdr) { return (struct xfs_dir2_data_entry *) ((char *)hdr + sizeof(struct xfs_dir2_data_hdr) + XFS_DIR2_DATA_ENTSIZE(1)); } static struct xfs_dir2_data_entry * xfs_dir2_data_first_entry_p( struct xfs_dir2_data_hdr *hdr) { return (struct xfs_dir2_data_entry *) ((char *)hdr + sizeof(struct xfs_dir2_data_hdr) + XFS_DIR2_DATA_ENTSIZE(1) + XFS_DIR2_DATA_ENTSIZE(2)); } static struct xfs_dir2_data_entry * xfs_dir2_ftype_data_dotdot_entry_p( struct xfs_dir2_data_hdr *hdr) { return (struct xfs_dir2_data_entry *) ((char *)hdr + sizeof(struct xfs_dir2_data_hdr) + XFS_DIR3_DATA_ENTSIZE(1)); } static struct xfs_dir2_data_entry * xfs_dir2_ftype_data_first_entry_p( struct xfs_dir2_data_hdr *hdr) { return (struct xfs_dir2_data_entry *) ((char *)hdr + sizeof(struct xfs_dir2_data_hdr) + XFS_DIR3_DATA_ENTSIZE(1) + XFS_DIR3_DATA_ENTSIZE(2)); } static struct xfs_dir2_data_entry * xfs_dir3_data_dot_entry_p( struct xfs_dir2_data_hdr *hdr) { return (struct xfs_dir2_data_entry *) ((char *)hdr + sizeof(struct xfs_dir3_data_hdr)); } static struct xfs_dir2_data_entry * xfs_dir3_data_dotdot_entry_p( struct xfs_dir2_data_hdr *hdr) { return (struct xfs_dir2_data_entry *) ((char *)hdr + sizeof(struct xfs_dir3_data_hdr) + XFS_DIR3_DATA_ENTSIZE(1)); } static struct xfs_dir2_data_entry * xfs_dir3_data_first_entry_p( struct xfs_dir2_data_hdr *hdr) { return (struct xfs_dir2_data_entry *) ((char *)hdr + sizeof(struct xfs_dir3_data_hdr) + XFS_DIR3_DATA_ENTSIZE(1) + XFS_DIR3_DATA_ENTSIZE(2)); } static struct xfs_dir2_data_free * xfs_dir2_data_bestfree_p(struct xfs_dir2_data_hdr *hdr) { return hdr->bestfree; } static struct xfs_dir2_data_free * xfs_dir3_data_bestfree_p(struct xfs_dir2_data_hdr *hdr) { return ((struct xfs_dir3_data_hdr *)hdr)->best_free; } static struct xfs_dir2_data_entry * xfs_dir2_data_entry_p(struct xfs_dir2_data_hdr *hdr) { return (struct xfs_dir2_data_entry *) ((char *)hdr + sizeof(struct xfs_dir2_data_hdr)); } static struct xfs_dir2_data_unused * xfs_dir2_data_unused_p(struct xfs_dir2_data_hdr *hdr) { return (struct xfs_dir2_data_unused *) ((char *)hdr + sizeof(struct xfs_dir2_data_hdr)); } static struct xfs_dir2_data_entry * xfs_dir3_data_entry_p(struct xfs_dir2_data_hdr *hdr) { return (struct xfs_dir2_data_entry *) ((char *)hdr + sizeof(struct xfs_dir3_data_hdr)); } static struct xfs_dir2_data_unused * xfs_dir3_data_unused_p(struct xfs_dir2_data_hdr *hdr) { return (struct xfs_dir2_data_unused *) ((char *)hdr + sizeof(struct xfs_dir3_data_hdr)); } /* * Directory Leaf block operations */ static int xfs_dir2_max_leaf_ents(struct xfs_da_geometry *geo) { return (geo->blksize - sizeof(struct xfs_dir2_leaf_hdr)) / (uint)sizeof(struct xfs_dir2_leaf_entry); } static struct xfs_dir2_leaf_entry * xfs_dir2_leaf_ents_p(struct xfs_dir2_leaf *lp) { return lp->__ents; } static int xfs_dir3_max_leaf_ents(struct xfs_da_geometry *geo) { return (geo->blksize - sizeof(struct xfs_dir3_leaf_hdr)) / (uint)sizeof(struct xfs_dir2_leaf_entry); } static struct xfs_dir2_leaf_entry * xfs_dir3_leaf_ents_p(struct xfs_dir2_leaf *lp) { return ((struct xfs_dir3_leaf *)lp)->__ents; } static void xfs_dir2_leaf_hdr_from_disk( struct xfs_dir3_icleaf_hdr *to, struct xfs_dir2_leaf *from) { to->forw = be32_to_cpu(from->hdr.info.forw); to->back = be32_to_cpu(from->hdr.info.back); to->magic = be16_to_cpu(from->hdr.info.magic); to->count = be16_to_cpu(from->hdr.count); to->stale = be16_to_cpu(from->hdr.stale); ASSERT(to->magic == XFS_DIR2_LEAF1_MAGIC || to->magic == XFS_DIR2_LEAFN_MAGIC); } static void xfs_dir2_leaf_hdr_to_disk( struct xfs_dir2_leaf *to, struct xfs_dir3_icleaf_hdr *from) { ASSERT(from->magic == XFS_DIR2_LEAF1_MAGIC || from->magic == XFS_DIR2_LEAFN_MAGIC); to->hdr.info.forw = cpu_to_be32(from->forw); to->hdr.info.back = cpu_to_be32(from->back); to->hdr.info.magic = cpu_to_be16(from->magic); to->hdr.count = cpu_to_be16(from->count); to->hdr.stale = cpu_to_be16(from->stale); } static void xfs_dir3_leaf_hdr_from_disk( struct xfs_dir3_icleaf_hdr *to, struct xfs_dir2_leaf *from) { struct xfs_dir3_leaf_hdr *hdr3 = (struct xfs_dir3_leaf_hdr *)from; to->forw = be32_to_cpu(hdr3->info.hdr.forw); to->back = be32_to_cpu(hdr3->info.hdr.back); to->magic = be16_to_cpu(hdr3->info.hdr.magic); to->count = be16_to_cpu(hdr3->count); to->stale = be16_to_cpu(hdr3->stale); ASSERT(to->magic == XFS_DIR3_LEAF1_MAGIC || to->magic == XFS_DIR3_LEAFN_MAGIC); } static void xfs_dir3_leaf_hdr_to_disk( struct xfs_dir2_leaf *to, struct xfs_dir3_icleaf_hdr *from) { struct xfs_dir3_leaf_hdr *hdr3 = (struct xfs_dir3_leaf_hdr *)to; ASSERT(from->magic == XFS_DIR3_LEAF1_MAGIC || from->magic == XFS_DIR3_LEAFN_MAGIC); hdr3->info.hdr.forw = cpu_to_be32(from->forw); hdr3->info.hdr.back = cpu_to_be32(from->back); hdr3->info.hdr.magic = cpu_to_be16(from->magic); hdr3->count = cpu_to_be16(from->count); hdr3->stale = cpu_to_be16(from->stale); } /* * Directory/Attribute Node block operations */ static struct xfs_da_node_entry * xfs_da2_node_tree_p(struct xfs_da_intnode *dap) { return dap->__btree; } static struct xfs_da_node_entry * xfs_da3_node_tree_p(struct xfs_da_intnode *dap) { return ((struct xfs_da3_intnode *)dap)->__btree; } static void xfs_da2_node_hdr_from_disk( struct xfs_da3_icnode_hdr *to, struct xfs_da_intnode *from) { ASSERT(from->hdr.info.magic == cpu_to_be16(XFS_DA_NODE_MAGIC)); to->forw = be32_to_cpu(from->hdr.info.forw); to->back = be32_to_cpu(from->hdr.info.back); to->magic = be16_to_cpu(from->hdr.info.magic); to->count = be16_to_cpu(from->hdr.__count); to->level = be16_to_cpu(from->hdr.__level); } static void xfs_da2_node_hdr_to_disk( struct xfs_da_intnode *to, struct xfs_da3_icnode_hdr *from) { ASSERT(from->magic == XFS_DA_NODE_MAGIC); to->hdr.info.forw = cpu_to_be32(from->forw); to->hdr.info.back = cpu_to_be32(from->back); to->hdr.info.magic = cpu_to_be16(from->magic); to->hdr.__count = cpu_to_be16(from->count); to->hdr.__level = cpu_to_be16(from->level); } static void xfs_da3_node_hdr_from_disk( struct xfs_da3_icnode_hdr *to, struct xfs_da_intnode *from) { struct xfs_da3_node_hdr *hdr3 = (struct xfs_da3_node_hdr *)from; ASSERT(from->hdr.info.magic == cpu_to_be16(XFS_DA3_NODE_MAGIC)); to->forw = be32_to_cpu(hdr3->info.hdr.forw); to->back = be32_to_cpu(hdr3->info.hdr.back); to->magic = be16_to_cpu(hdr3->info.hdr.magic); to->count = be16_to_cpu(hdr3->__count); to->level = be16_to_cpu(hdr3->__level); } static void xfs_da3_node_hdr_to_disk( struct xfs_da_intnode *to, struct xfs_da3_icnode_hdr *from) { struct xfs_da3_node_hdr *hdr3 = (struct xfs_da3_node_hdr *)to; ASSERT(from->magic == XFS_DA3_NODE_MAGIC); hdr3->info.hdr.forw = cpu_to_be32(from->forw); hdr3->info.hdr.back = cpu_to_be32(from->back); hdr3->info.hdr.magic = cpu_to_be16(from->magic); hdr3->__count = cpu_to_be16(from->count); hdr3->__level = cpu_to_be16(from->level); } /* * Directory free space block operations */ static int xfs_dir2_free_max_bests(struct xfs_da_geometry *geo) { return (geo->blksize - sizeof(struct xfs_dir2_free_hdr)) / sizeof(xfs_dir2_data_off_t); } static __be16 * xfs_dir2_free_bests_p(struct xfs_dir2_free *free) { return (__be16 *)((char *)free + sizeof(struct xfs_dir2_free_hdr)); } /* * Convert data space db to the corresponding free db. */ static xfs_dir2_db_t xfs_dir2_db_to_fdb(struct xfs_da_geometry *geo, xfs_dir2_db_t db) { return xfs_dir2_byte_to_db(geo, XFS_DIR2_FREE_OFFSET) + (db / xfs_dir2_free_max_bests(geo)); } /* * Convert data space db to the corresponding index in a free db. */ static int xfs_dir2_db_to_fdindex(struct xfs_da_geometry *geo, xfs_dir2_db_t db) { return db % xfs_dir2_free_max_bests(geo); } static int xfs_dir3_free_max_bests(struct xfs_da_geometry *geo) { return (geo->blksize - sizeof(struct xfs_dir3_free_hdr)) / sizeof(xfs_dir2_data_off_t); } static __be16 * xfs_dir3_free_bests_p(struct xfs_dir2_free *free) { return (__be16 *)((char *)free + sizeof(struct xfs_dir3_free_hdr)); } /* * Convert data space db to the corresponding free db. */ static xfs_dir2_db_t xfs_dir3_db_to_fdb(struct xfs_da_geometry *geo, xfs_dir2_db_t db) { return xfs_dir2_byte_to_db(geo, XFS_DIR2_FREE_OFFSET) + (db / xfs_dir3_free_max_bests(geo)); } /* * Convert data space db to the corresponding index in a free db. */ static int xfs_dir3_db_to_fdindex(struct xfs_da_geometry *geo, xfs_dir2_db_t db) { return db % xfs_dir3_free_max_bests(geo); } static void xfs_dir2_free_hdr_from_disk( struct xfs_dir3_icfree_hdr *to, struct xfs_dir2_free *from) { to->magic = be32_to_cpu(from->hdr.magic); to->firstdb = be32_to_cpu(from->hdr.firstdb); to->nvalid = be32_to_cpu(from->hdr.nvalid); to->nused = be32_to_cpu(from->hdr.nused); ASSERT(to->magic == XFS_DIR2_FREE_MAGIC); } static void xfs_dir2_free_hdr_to_disk( struct xfs_dir2_free *to, struct xfs_dir3_icfree_hdr *from) { ASSERT(from->magic == XFS_DIR2_FREE_MAGIC); to->hdr.magic = cpu_to_be32(from->magic); to->hdr.firstdb = cpu_to_be32(from->firstdb); to->hdr.nvalid = cpu_to_be32(from->nvalid); to->hdr.nused = cpu_to_be32(from->nused); } static void xfs_dir3_free_hdr_from_disk( struct xfs_dir3_icfree_hdr *to, struct xfs_dir2_free *from) { struct xfs_dir3_free_hdr *hdr3 = (struct xfs_dir3_free_hdr *)from; to->magic = be32_to_cpu(hdr3->hdr.magic); to->firstdb = be32_to_cpu(hdr3->firstdb); to->nvalid = be32_to_cpu(hdr3->nvalid); to->nused = be32_to_cpu(hdr3->nused); ASSERT(to->magic == XFS_DIR3_FREE_MAGIC); } static void xfs_dir3_free_hdr_to_disk( struct xfs_dir2_free *to, struct xfs_dir3_icfree_hdr *from) { struct xfs_dir3_free_hdr *hdr3 = (struct xfs_dir3_free_hdr *)to; ASSERT(from->magic == XFS_DIR3_FREE_MAGIC); hdr3->hdr.magic = cpu_to_be32(from->magic); hdr3->firstdb = cpu_to_be32(from->firstdb); hdr3->nvalid = cpu_to_be32(from->nvalid); hdr3->nused = cpu_to_be32(from->nused); } static const struct xfs_dir_ops xfs_dir2_ops = { .sf_entsize = xfs_dir2_sf_entsize, .sf_nextentry = xfs_dir2_sf_nextentry, .sf_get_ftype = xfs_dir2_sfe_get_ftype, .sf_put_ftype = xfs_dir2_sfe_put_ftype, .sf_get_ino = xfs_dir2_sfe_get_ino, .sf_put_ino = xfs_dir2_sfe_put_ino, .sf_get_parent_ino = xfs_dir2_sf_get_parent_ino, .sf_put_parent_ino = xfs_dir2_sf_put_parent_ino, .data_entsize = xfs_dir2_data_entsize, .data_get_ftype = xfs_dir2_data_get_ftype, .data_put_ftype = xfs_dir2_data_put_ftype, .data_entry_tag_p = xfs_dir2_data_entry_tag_p, .data_bestfree_p = xfs_dir2_data_bestfree_p, .data_dot_offset = sizeof(struct xfs_dir2_data_hdr), .data_dotdot_offset = sizeof(struct xfs_dir2_data_hdr) + XFS_DIR2_DATA_ENTSIZE(1), .data_first_offset = sizeof(struct xfs_dir2_data_hdr) + XFS_DIR2_DATA_ENTSIZE(1) + XFS_DIR2_DATA_ENTSIZE(2), .data_entry_offset = sizeof(struct xfs_dir2_data_hdr), .data_dot_entry_p = xfs_dir2_data_dot_entry_p, .data_dotdot_entry_p = xfs_dir2_data_dotdot_entry_p, .data_first_entry_p = xfs_dir2_data_first_entry_p, .data_entry_p = xfs_dir2_data_entry_p, .data_unused_p = xfs_dir2_data_unused_p, .leaf_hdr_size = sizeof(struct xfs_dir2_leaf_hdr), .leaf_hdr_to_disk = xfs_dir2_leaf_hdr_to_disk, .leaf_hdr_from_disk = xfs_dir2_leaf_hdr_from_disk, .leaf_max_ents = xfs_dir2_max_leaf_ents, .leaf_ents_p = xfs_dir2_leaf_ents_p, .node_hdr_size = sizeof(struct xfs_da_node_hdr), .node_hdr_to_disk = xfs_da2_node_hdr_to_disk, .node_hdr_from_disk = xfs_da2_node_hdr_from_disk, .node_tree_p = xfs_da2_node_tree_p, .free_hdr_size = sizeof(struct xfs_dir2_free_hdr), .free_hdr_to_disk = xfs_dir2_free_hdr_to_disk, .free_hdr_from_disk = xfs_dir2_free_hdr_from_disk, .free_max_bests = xfs_dir2_free_max_bests, .free_bests_p = xfs_dir2_free_bests_p, .db_to_fdb = xfs_dir2_db_to_fdb, .db_to_fdindex = xfs_dir2_db_to_fdindex, }; static const struct xfs_dir_ops xfs_dir2_ftype_ops = { .sf_entsize = xfs_dir3_sf_entsize, .sf_nextentry = xfs_dir3_sf_nextentry, .sf_get_ftype = xfs_dir3_sfe_get_ftype, .sf_put_ftype = xfs_dir3_sfe_put_ftype, .sf_get_ino = xfs_dir3_sfe_get_ino, .sf_put_ino = xfs_dir3_sfe_put_ino, .sf_get_parent_ino = xfs_dir2_sf_get_parent_ino, .sf_put_parent_ino = xfs_dir2_sf_put_parent_ino, .data_entsize = xfs_dir3_data_entsize, .data_get_ftype = xfs_dir3_data_get_ftype, .data_put_ftype = xfs_dir3_data_put_ftype, .data_entry_tag_p = xfs_dir3_data_entry_tag_p, .data_bestfree_p = xfs_dir2_data_bestfree_p, .data_dot_offset = sizeof(struct xfs_dir2_data_hdr), .data_dotdot_offset = sizeof(struct xfs_dir2_data_hdr) + XFS_DIR3_DATA_ENTSIZE(1), .data_first_offset = sizeof(struct xfs_dir2_data_hdr) + XFS_DIR3_DATA_ENTSIZE(1) + XFS_DIR3_DATA_ENTSIZE(2), .data_entry_offset = sizeof(struct xfs_dir2_data_hdr), .data_dot_entry_p = xfs_dir2_data_dot_entry_p, .data_dotdot_entry_p = xfs_dir2_ftype_data_dotdot_entry_p, .data_first_entry_p = xfs_dir2_ftype_data_first_entry_p, .data_entry_p = xfs_dir2_data_entry_p, .data_unused_p = xfs_dir2_data_unused_p, .leaf_hdr_size = sizeof(struct xfs_dir2_leaf_hdr), .leaf_hdr_to_disk = xfs_dir2_leaf_hdr_to_disk, .leaf_hdr_from_disk = xfs_dir2_leaf_hdr_from_disk, .leaf_max_ents = xfs_dir2_max_leaf_ents, .leaf_ents_p = xfs_dir2_leaf_ents_p, .node_hdr_size = sizeof(struct xfs_da_node_hdr), .node_hdr_to_disk = xfs_da2_node_hdr_to_disk, .node_hdr_from_disk = xfs_da2_node_hdr_from_disk, .node_tree_p = xfs_da2_node_tree_p, .free_hdr_size = sizeof(struct xfs_dir2_free_hdr), .free_hdr_to_disk = xfs_dir2_free_hdr_to_disk, .free_hdr_from_disk = xfs_dir2_free_hdr_from_disk, .free_max_bests = xfs_dir2_free_max_bests, .free_bests_p = xfs_dir2_free_bests_p, .db_to_fdb = xfs_dir2_db_to_fdb, .db_to_fdindex = xfs_dir2_db_to_fdindex, }; static const struct xfs_dir_ops xfs_dir3_ops = { .sf_entsize = xfs_dir3_sf_entsize, .sf_nextentry = xfs_dir3_sf_nextentry, .sf_get_ftype = xfs_dir3_sfe_get_ftype, .sf_put_ftype = xfs_dir3_sfe_put_ftype, .sf_get_ino = xfs_dir3_sfe_get_ino, .sf_put_ino = xfs_dir3_sfe_put_ino, .sf_get_parent_ino = xfs_dir2_sf_get_parent_ino, .sf_put_parent_ino = xfs_dir2_sf_put_parent_ino, .data_entsize = xfs_dir3_data_entsize, .data_get_ftype = xfs_dir3_data_get_ftype, .data_put_ftype = xfs_dir3_data_put_ftype, .data_entry_tag_p = xfs_dir3_data_entry_tag_p, .data_bestfree_p = xfs_dir3_data_bestfree_p, .data_dot_offset = sizeof(struct xfs_dir3_data_hdr), .data_dotdot_offset = sizeof(struct xfs_dir3_data_hdr) + XFS_DIR3_DATA_ENTSIZE(1), .data_first_offset = sizeof(struct xfs_dir3_data_hdr) + XFS_DIR3_DATA_ENTSIZE(1) + XFS_DIR3_DATA_ENTSIZE(2), .data_entry_offset = sizeof(struct xfs_dir3_data_hdr), .data_dot_entry_p = xfs_dir3_data_dot_entry_p, .data_dotdot_entry_p = xfs_dir3_data_dotdot_entry_p, .data_first_entry_p = xfs_dir3_data_first_entry_p, .data_entry_p = xfs_dir3_data_entry_p, .data_unused_p = xfs_dir3_data_unused_p, .leaf_hdr_size = sizeof(struct xfs_dir3_leaf_hdr), .leaf_hdr_to_disk = xfs_dir3_leaf_hdr_to_disk, .leaf_hdr_from_disk = xfs_dir3_leaf_hdr_from_disk, .leaf_max_ents = xfs_dir3_max_leaf_ents, .leaf_ents_p = xfs_dir3_leaf_ents_p, .node_hdr_size = sizeof(struct xfs_da3_node_hdr), .node_hdr_to_disk = xfs_da3_node_hdr_to_disk, .node_hdr_from_disk = xfs_da3_node_hdr_from_disk, .node_tree_p = xfs_da3_node_tree_p, .free_hdr_size = sizeof(struct xfs_dir3_free_hdr), .free_hdr_to_disk = xfs_dir3_free_hdr_to_disk, .free_hdr_from_disk = xfs_dir3_free_hdr_from_disk, .free_max_bests = xfs_dir3_free_max_bests, .free_bests_p = xfs_dir3_free_bests_p, .db_to_fdb = xfs_dir3_db_to_fdb, .db_to_fdindex = xfs_dir3_db_to_fdindex, }; static const struct xfs_dir_ops xfs_dir2_nondir_ops = { .node_hdr_size = sizeof(struct xfs_da_node_hdr), .node_hdr_to_disk = xfs_da2_node_hdr_to_disk, .node_hdr_from_disk = xfs_da2_node_hdr_from_disk, .node_tree_p = xfs_da2_node_tree_p, }; static const struct xfs_dir_ops xfs_dir3_nondir_ops = { .node_hdr_size = sizeof(struct xfs_da3_node_hdr), .node_hdr_to_disk = xfs_da3_node_hdr_to_disk, .node_hdr_from_disk = xfs_da3_node_hdr_from_disk, .node_tree_p = xfs_da3_node_tree_p, }; /* * Return the ops structure according to the current config. If we are passed * an inode, then that overrides the default config we use which is based on * feature bits. */ const struct xfs_dir_ops * xfs_dir_get_ops( struct xfs_mount *mp, struct xfs_inode *dp) { if (dp) return dp->d_ops; if (mp->m_dir_inode_ops) return mp->m_dir_inode_ops; if (xfs_sb_version_hascrc(&mp->m_sb)) return &xfs_dir3_ops; if (xfs_sb_version_hasftype(&mp->m_sb)) return &xfs_dir2_ftype_ops; return &xfs_dir2_ops; } const struct xfs_dir_ops * xfs_nondir_get_ops( struct xfs_mount *mp, struct xfs_inode *dp) { if (dp) return dp->d_ops; if (mp->m_nondir_inode_ops) return mp->m_nondir_inode_ops; if (xfs_sb_version_hascrc(&mp->m_sb)) return &xfs_dir3_nondir_ops; return &xfs_dir2_nondir_ops; } partclone-0.2.86/src/xfs/xfs_da_format.h000066400000000000000000000717121262102574200201630ustar00rootroot00000000000000/* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * Copyright (c) 2013 Red Hat, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __XFS_DA_FORMAT_H__ #define __XFS_DA_FORMAT_H__ /* * This structure is common to both leaf nodes and non-leaf nodes in the Btree. * * It is used to manage a doubly linked list of all blocks at the same * level in the Btree, and to identify which type of block this is. */ #define XFS_DA_NODE_MAGIC 0xfebe /* magic number: non-leaf blocks */ #define XFS_ATTR_LEAF_MAGIC 0xfbee /* magic number: attribute leaf blks */ #define XFS_DIR2_LEAF1_MAGIC 0xd2f1 /* magic number: v2 dirlf single blks */ #define XFS_DIR2_LEAFN_MAGIC 0xd2ff /* magic number: v2 dirlf multi blks */ typedef struct xfs_da_blkinfo { __be32 forw; /* previous block in list */ __be32 back; /* following block in list */ __be16 magic; /* validity check on block */ __be16 pad; /* unused */ } xfs_da_blkinfo_t; /* * CRC enabled directory structure types * * The headers change size for the additional verification information, but * otherwise the tree layouts and contents are unchanged. Hence the da btree * code can use the struct xfs_da_blkinfo for manipulating the tree links and * magic numbers without modification for both v2 and v3 nodes. */ #define XFS_DA3_NODE_MAGIC 0x3ebe /* magic number: non-leaf blocks */ #define XFS_ATTR3_LEAF_MAGIC 0x3bee /* magic number: attribute leaf blks */ #define XFS_DIR3_LEAF1_MAGIC 0x3df1 /* magic number: v2 dirlf single blks */ #define XFS_DIR3_LEAFN_MAGIC 0x3dff /* magic number: v2 dirlf multi blks */ struct xfs_da3_blkinfo { /* * the node link manipulation code relies on the fact that the first * element of this structure is the struct xfs_da_blkinfo so it can * ignore the differences in the rest of the structures. */ struct xfs_da_blkinfo hdr; __be32 crc; /* CRC of block */ __be64 blkno; /* first block of the buffer */ __be64 lsn; /* sequence number of last write */ uuid_t uuid; /* filesystem we belong to */ __be64 owner; /* inode that owns the block */ }; /* * This is the structure of the root and intermediate nodes in the Btree. * The leaf nodes are defined above. * * Entries are not packed. * * Since we have duplicate keys, use a binary search but always follow * all match in the block, not just the first match found. */ #define XFS_DA_NODE_MAXDEPTH 5 /* max depth of Btree */ typedef struct xfs_da_node_hdr { struct xfs_da_blkinfo info; /* block type, links, etc. */ __be16 __count; /* count of active entries */ __be16 __level; /* level above leaves (leaf == 0) */ } xfs_da_node_hdr_t; struct xfs_da3_node_hdr { struct xfs_da3_blkinfo info; /* block type, links, etc. */ __be16 __count; /* count of active entries */ __be16 __level; /* level above leaves (leaf == 0) */ __be32 __pad32; }; #define XFS_DA3_NODE_CRC_OFF (offsetof(struct xfs_da3_node_hdr, info.crc)) typedef struct xfs_da_node_entry { __be32 hashval; /* hash value for this descendant */ __be32 before; /* Btree block before this key */ } xfs_da_node_entry_t; typedef struct xfs_da_intnode { struct xfs_da_node_hdr hdr; struct xfs_da_node_entry __btree[]; } xfs_da_intnode_t; struct xfs_da3_intnode { struct xfs_da3_node_hdr hdr; struct xfs_da_node_entry __btree[]; }; /* * In-core version of the node header to abstract the differences in the v2 and * v3 disk format of the headers. Callers need to convert to/from disk format as * appropriate. */ struct xfs_da3_icnode_hdr { __uint32_t forw; __uint32_t back; __uint16_t magic; __uint16_t count; __uint16_t level; }; /* * Directory version 2. * * There are 4 possible formats: * - shortform - embedded into the inode * - single block - data with embedded leaf at the end * - multiple data blocks, single leaf+freeindex block * - data blocks, node and leaf blocks (btree), freeindex blocks * * Note: many node blocks structures and constants are shared with the attr * code and defined in xfs_da_btree.h. */ #define XFS_DIR2_BLOCK_MAGIC 0x58443242 /* XD2B: single block dirs */ #define XFS_DIR2_DATA_MAGIC 0x58443244 /* XD2D: multiblock dirs */ #define XFS_DIR2_FREE_MAGIC 0x58443246 /* XD2F: free index blocks */ /* * Directory Version 3 With CRCs. * * The tree formats are the same as for version 2 directories. The difference * is in the block header and dirent formats. In many cases the v3 structures * use v2 definitions as they are no different and this makes code sharing much * easier. * * Also, the xfs_dir3_*() functions handle both v2 and v3 formats - if the * format is v2 then they switch to the existing v2 code, or the format is v3 * they implement the v3 functionality. This means the existing dir2 is a mix of * xfs_dir2/xfs_dir3 calls and functions. The xfs_dir3 functions are called * where there is a difference in the formats, otherwise the code is unchanged. * * Where it is possible, the code decides what to do based on the magic numbers * in the blocks rather than feature bits in the superblock. This means the code * is as independent of the external XFS code as possible as doesn't require * passing struct xfs_mount pointers into places where it isn't really * necessary. * * Version 3 includes: * * - a larger block header for CRC and identification purposes and so the * offsets of all the structures inside the blocks are different. * * - new magic numbers to be able to detect the v2/v3 types on the fly. */ #define XFS_DIR3_BLOCK_MAGIC 0x58444233 /* XDB3: single block dirs */ #define XFS_DIR3_DATA_MAGIC 0x58444433 /* XDD3: multiblock dirs */ #define XFS_DIR3_FREE_MAGIC 0x58444633 /* XDF3: free index blocks */ /* * Dirents in version 3 directories have a file type field. Additions to this * list are an on-disk format change, requiring feature bits. Valid values * are as follows: */ #define XFS_DIR3_FT_UNKNOWN 0 #define XFS_DIR3_FT_REG_FILE 1 #define XFS_DIR3_FT_DIR 2 #define XFS_DIR3_FT_CHRDEV 3 #define XFS_DIR3_FT_BLKDEV 4 #define XFS_DIR3_FT_FIFO 5 #define XFS_DIR3_FT_SOCK 6 #define XFS_DIR3_FT_SYMLINK 7 #define XFS_DIR3_FT_WHT 8 #define XFS_DIR3_FT_MAX 9 /* * Byte offset in data block and shortform entry. */ typedef __uint16_t xfs_dir2_data_off_t; #define NULLDATAOFF 0xffffU typedef uint xfs_dir2_data_aoff_t; /* argument form */ /* * Normalized offset (in a data block) of the entry, really xfs_dir2_data_off_t. * Only need 16 bits, this is the byte offset into the single block form. */ typedef struct { __uint8_t i[2]; } __arch_pack xfs_dir2_sf_off_t; /* * Offset in data space of a data entry. */ typedef __uint32_t xfs_dir2_dataptr_t; #define XFS_DIR2_MAX_DATAPTR ((xfs_dir2_dataptr_t)0xffffffff) #define XFS_DIR2_NULL_DATAPTR ((xfs_dir2_dataptr_t)0) /* * Byte offset in a directory. */ typedef xfs_off_t xfs_dir2_off_t; /* * Directory block number (logical dirblk in file) */ typedef __uint32_t xfs_dir2_db_t; /* * Inode number stored as 8 8-bit values. */ typedef struct { __uint8_t i[8]; } xfs_dir2_ino8_t; /* * Inode number stored as 4 8-bit values. * Works a lot of the time, when all the inode numbers in a directory * fit in 32 bits. */ typedef struct { __uint8_t i[4]; } xfs_dir2_ino4_t; typedef union { xfs_dir2_ino8_t i8; xfs_dir2_ino4_t i4; } xfs_dir2_inou_t; #define XFS_DIR2_MAX_SHORT_INUM ((xfs_ino_t)0xffffffffULL) /* * Directory layout when stored internal to an inode. * * Small directories are packed as tightly as possible so as to fit into the * literal area of the inode. These "shortform" directories consist of a * single xfs_dir2_sf_hdr header followed by zero or more xfs_dir2_sf_entry * structures. Due the different inode number storage size and the variable * length name field in the xfs_dir2_sf_entry all these structure are * variable length, and the accessors in this file should be used to iterate * over them. */ typedef struct xfs_dir2_sf_hdr { __uint8_t count; /* count of entries */ __uint8_t i8count; /* count of 8-byte inode #s */ xfs_dir2_inou_t parent; /* parent dir inode number */ } __arch_pack xfs_dir2_sf_hdr_t; typedef struct xfs_dir2_sf_entry { __u8 namelen; /* actual name length */ xfs_dir2_sf_off_t offset; /* saved offset */ __u8 name[]; /* name, variable size */ /* * A single byte containing the file type field follows the inode * number for version 3 directory entries. * * A xfs_dir2_ino8_t or xfs_dir2_ino4_t follows here, at a * variable offset after the name. */ } __arch_pack xfs_dir2_sf_entry_t; static inline int xfs_dir2_sf_hdr_size(int i8count) { return sizeof(struct xfs_dir2_sf_hdr) - (i8count == 0) * (sizeof(xfs_dir2_ino8_t) - sizeof(xfs_dir2_ino4_t)); } static inline xfs_dir2_data_aoff_t xfs_dir2_sf_get_offset(xfs_dir2_sf_entry_t *sfep) { return get_unaligned_be16(&sfep->offset.i); } static inline void xfs_dir2_sf_put_offset(xfs_dir2_sf_entry_t *sfep, xfs_dir2_data_aoff_t off) { put_unaligned_be16(off, &sfep->offset.i); } static inline struct xfs_dir2_sf_entry * xfs_dir2_sf_firstentry(struct xfs_dir2_sf_hdr *hdr) { return (struct xfs_dir2_sf_entry *) ((char *)hdr + xfs_dir2_sf_hdr_size(hdr->i8count)); } /* * Data block structures. * * A pure data block looks like the following drawing on disk: * * +-------------------------------------------------+ * | xfs_dir2_data_hdr_t | * +-------------------------------------------------+ * | xfs_dir2_data_entry_t OR xfs_dir2_data_unused_t | * | xfs_dir2_data_entry_t OR xfs_dir2_data_unused_t | * | xfs_dir2_data_entry_t OR xfs_dir2_data_unused_t | * | ... | * +-------------------------------------------------+ * | unused space | * +-------------------------------------------------+ * * As all the entries are variable size structures the accessors below should * be used to iterate over them. * * In addition to the pure data blocks for the data and node formats, * most structures are also used for the combined data/freespace "block" * format below. */ #define XFS_DIR2_DATA_ALIGN_LOG 3 /* i.e., 8 bytes */ #define XFS_DIR2_DATA_ALIGN (1 << XFS_DIR2_DATA_ALIGN_LOG) #define XFS_DIR2_DATA_FREE_TAG 0xffff #define XFS_DIR2_DATA_FD_COUNT 3 /* * Directory address space divided into sections, * spaces separated by 32GB. */ #define XFS_DIR2_SPACE_SIZE (1ULL << (32 + XFS_DIR2_DATA_ALIGN_LOG)) #define XFS_DIR2_DATA_SPACE 0 #define XFS_DIR2_DATA_OFFSET (XFS_DIR2_DATA_SPACE * XFS_DIR2_SPACE_SIZE) /* * Describe a free area in the data block. * * The freespace will be formatted as a xfs_dir2_data_unused_t. */ typedef struct xfs_dir2_data_free { __be16 offset; /* start of freespace */ __be16 length; /* length of freespace */ } xfs_dir2_data_free_t; /* * Header for the data blocks. * * The code knows that XFS_DIR2_DATA_FD_COUNT is 3. */ typedef struct xfs_dir2_data_hdr { __be32 magic; /* XFS_DIR2_DATA_MAGIC or */ /* XFS_DIR2_BLOCK_MAGIC */ xfs_dir2_data_free_t bestfree[XFS_DIR2_DATA_FD_COUNT]; } xfs_dir2_data_hdr_t; /* * define a structure for all the verification fields we are adding to the * directory block structures. This will be used in several structures. * The magic number must be the first entry to align with all the dir2 * structures so we determine how to decode them just by the magic number. */ struct xfs_dir3_blk_hdr { __be32 magic; /* magic number */ __be32 crc; /* CRC of block */ __be64 blkno; /* first block of the buffer */ __be64 lsn; /* sequence number of last write */ uuid_t uuid; /* filesystem we belong to */ __be64 owner; /* inode that owns the block */ }; struct xfs_dir3_data_hdr { struct xfs_dir3_blk_hdr hdr; xfs_dir2_data_free_t best_free[XFS_DIR2_DATA_FD_COUNT]; __be32 pad; /* 64 bit alignment */ }; #define XFS_DIR3_DATA_CRC_OFF offsetof(struct xfs_dir3_data_hdr, hdr.crc) /* * Active entry in a data block. * * Aligned to 8 bytes. After the variable length name field there is a * 2 byte tag field, which can be accessed using xfs_dir3_data_entry_tag_p. * * For dir3 structures, there is file type field between the name and the tag. * This can only be manipulated by helper functions. It is packed hard against * the end of the name so any padding for rounding is between the file type and * the tag. */ typedef struct xfs_dir2_data_entry { __be64 inumber; /* inode number */ __u8 namelen; /* name length */ __u8 name[]; /* name bytes, no null */ /* __u8 filetype; */ /* type of inode we point to */ /* __be16 tag; */ /* starting offset of us */ } xfs_dir2_data_entry_t; /* * Unused entry in a data block. * * Aligned to 8 bytes. Tag appears as the last 2 bytes and must be accessed * using xfs_dir2_data_unused_tag_p. */ typedef struct xfs_dir2_data_unused { __be16 freetag; /* XFS_DIR2_DATA_FREE_TAG */ __be16 length; /* total free length */ /* variable offset */ __be16 tag; /* starting offset of us */ } xfs_dir2_data_unused_t; /* * Pointer to a freespace's tag word. */ static inline __be16 * xfs_dir2_data_unused_tag_p(struct xfs_dir2_data_unused *dup) { return (__be16 *)((char *)dup + be16_to_cpu(dup->length) - sizeof(__be16)); } /* * Leaf block structures. * * A pure leaf block looks like the following drawing on disk: * * +---------------------------+ * | xfs_dir2_leaf_hdr_t | * +---------------------------+ * | xfs_dir2_leaf_entry_t | * | xfs_dir2_leaf_entry_t | * | xfs_dir2_leaf_entry_t | * | xfs_dir2_leaf_entry_t | * | ... | * +---------------------------+ * | xfs_dir2_data_off_t | * | xfs_dir2_data_off_t | * | xfs_dir2_data_off_t | * | ... | * +---------------------------+ * | xfs_dir2_leaf_tail_t | * +---------------------------+ * * The xfs_dir2_data_off_t members (bests) and tail are at the end of the block * for single-leaf (magic = XFS_DIR2_LEAF1_MAGIC) blocks only, but not present * for directories with separate leaf nodes and free space blocks * (magic = XFS_DIR2_LEAFN_MAGIC). * * As all the entries are variable size structures the accessors below should * be used to iterate over them. */ /* * Offset of the leaf/node space. First block in this space * is the btree root. */ #define XFS_DIR2_LEAF_SPACE 1 #define XFS_DIR2_LEAF_OFFSET (XFS_DIR2_LEAF_SPACE * XFS_DIR2_SPACE_SIZE) /* * Leaf block header. */ typedef struct xfs_dir2_leaf_hdr { xfs_da_blkinfo_t info; /* header for da routines */ __be16 count; /* count of entries */ __be16 stale; /* count of stale entries */ } xfs_dir2_leaf_hdr_t; struct xfs_dir3_leaf_hdr { struct xfs_da3_blkinfo info; /* header for da routines */ __be16 count; /* count of entries */ __be16 stale; /* count of stale entries */ __be32 pad; /* 64 bit alignment */ }; struct xfs_dir3_icleaf_hdr { __uint32_t forw; __uint32_t back; __uint16_t magic; __uint16_t count; __uint16_t stale; }; /* * Leaf block entry. */ typedef struct xfs_dir2_leaf_entry { __be32 hashval; /* hash value of name */ __be32 address; /* address of data entry */ } xfs_dir2_leaf_entry_t; /* * Leaf block tail. */ typedef struct xfs_dir2_leaf_tail { __be32 bestcount; } xfs_dir2_leaf_tail_t; /* * Leaf block. */ typedef struct xfs_dir2_leaf { xfs_dir2_leaf_hdr_t hdr; /* leaf header */ xfs_dir2_leaf_entry_t __ents[]; /* entries */ } xfs_dir2_leaf_t; struct xfs_dir3_leaf { struct xfs_dir3_leaf_hdr hdr; /* leaf header */ struct xfs_dir2_leaf_entry __ents[]; /* entries */ }; #define XFS_DIR3_LEAF_CRC_OFF offsetof(struct xfs_dir3_leaf_hdr, info.crc) /* * Get address of the bests array in the single-leaf block. */ static inline __be16 * xfs_dir2_leaf_bests_p(struct xfs_dir2_leaf_tail *ltp) { return (__be16 *)ltp - be32_to_cpu(ltp->bestcount); } /* * Free space block defintions for the node format. */ /* * Offset of the freespace index. */ #define XFS_DIR2_FREE_SPACE 2 #define XFS_DIR2_FREE_OFFSET (XFS_DIR2_FREE_SPACE * XFS_DIR2_SPACE_SIZE) typedef struct xfs_dir2_free_hdr { __be32 magic; /* XFS_DIR2_FREE_MAGIC */ __be32 firstdb; /* db of first entry */ __be32 nvalid; /* count of valid entries */ __be32 nused; /* count of used entries */ } xfs_dir2_free_hdr_t; typedef struct xfs_dir2_free { xfs_dir2_free_hdr_t hdr; /* block header */ __be16 bests[]; /* best free counts */ /* unused entries are -1 */ } xfs_dir2_free_t; struct xfs_dir3_free_hdr { struct xfs_dir3_blk_hdr hdr; __be32 firstdb; /* db of first entry */ __be32 nvalid; /* count of valid entries */ __be32 nused; /* count of used entries */ __be32 pad; /* 64 bit alignment */ }; struct xfs_dir3_free { struct xfs_dir3_free_hdr hdr; __be16 bests[]; /* best free counts */ /* unused entries are -1 */ }; #define XFS_DIR3_FREE_CRC_OFF offsetof(struct xfs_dir3_free, hdr.hdr.crc) /* * In core version of the free block header, abstracted away from on-disk format * differences. Use this in the code, and convert to/from the disk version using * xfs_dir3_free_hdr_from_disk/xfs_dir3_free_hdr_to_disk. */ struct xfs_dir3_icfree_hdr { __uint32_t magic; __uint32_t firstdb; __uint32_t nvalid; __uint32_t nused; }; /* * Single block format. * * The single block format looks like the following drawing on disk: * * +-------------------------------------------------+ * | xfs_dir2_data_hdr_t | * +-------------------------------------------------+ * | xfs_dir2_data_entry_t OR xfs_dir2_data_unused_t | * | xfs_dir2_data_entry_t OR xfs_dir2_data_unused_t | * | xfs_dir2_data_entry_t OR xfs_dir2_data_unused_t : * | ... | * +-------------------------------------------------+ * | unused space | * +-------------------------------------------------+ * | ... | * | xfs_dir2_leaf_entry_t | * | xfs_dir2_leaf_entry_t | * +-------------------------------------------------+ * | xfs_dir2_block_tail_t | * +-------------------------------------------------+ * * As all the entries are variable size structures the accessors below should * be used to iterate over them. */ typedef struct xfs_dir2_block_tail { __be32 count; /* count of leaf entries */ __be32 stale; /* count of stale lf entries */ } xfs_dir2_block_tail_t; /* * Pointer to the leaf entries embedded in a data block (1-block format) */ static inline struct xfs_dir2_leaf_entry * xfs_dir2_block_leaf_p(struct xfs_dir2_block_tail *btp) { return ((struct xfs_dir2_leaf_entry *)btp) - be32_to_cpu(btp->count); } /* * Attribute storage layout * * Attribute lists are structured around Btrees where all the data * elements are in the leaf nodes. Attribute names are hashed into an int, * then that int is used as the index into the Btree. Since the hashval * of an attribute name may not be unique, we may have duplicate keys. The * internal links in the Btree are logical block offsets into the file. * * Struct leaf_entry's are packed from the top. Name/values grow from the * bottom but are not packed. The freemap contains run-length-encoded entries * for the free bytes after the leaf_entry's, but only the N largest such, * smaller runs are dropped. When the freemap doesn't show enough space * for an allocation, we compact the name/value area and try again. If we * still don't have enough space, then we have to split the block. The * name/value structs (both local and remote versions) must be 32bit aligned. * * Since we have duplicate hash keys, for each key that matches, compare * the actual name string. The root and intermediate node search always * takes the first-in-the-block key match found, so we should only have * to work "forw"ard. If none matches, continue with the "forw"ard leaf * nodes until the hash key changes or the attribute name is found. * * We store the fact that an attribute is a ROOT/USER/SECURE attribute in * the leaf_entry. The namespaces are independent only because we also look * at the namespace bit when we are looking for a matching attribute name. * * We also store an "incomplete" bit in the leaf_entry. It shows that an * attribute is in the middle of being created and should not be shown to * the user if we crash during the time that the bit is set. We clear the * bit when we have finished setting up the attribute. We do this because * we cannot create some large attributes inside a single transaction, and we * need some indication that we weren't finished if we crash in the middle. */ #define XFS_ATTR_LEAF_MAPSIZE 3 /* how many freespace slots */ typedef struct xfs_attr_leaf_map { /* RLE map of free bytes */ __be16 base; /* base of free region */ __be16 size; /* length of free region */ } xfs_attr_leaf_map_t; typedef struct xfs_attr_leaf_hdr { /* constant-structure header block */ xfs_da_blkinfo_t info; /* block type, links, etc. */ __be16 count; /* count of active leaf_entry's */ __be16 usedbytes; /* num bytes of names/values stored */ __be16 firstused; /* first used byte in name area */ __u8 holes; /* != 0 if blk needs compaction */ __u8 pad1; xfs_attr_leaf_map_t freemap[XFS_ATTR_LEAF_MAPSIZE]; /* N largest free regions */ } xfs_attr_leaf_hdr_t; typedef struct xfs_attr_leaf_entry { /* sorted on key, not name */ __be32 hashval; /* hash value of name */ __be16 nameidx; /* index into buffer of name/value */ __u8 flags; /* LOCAL/ROOT/SECURE/INCOMPLETE flag */ __u8 pad2; /* unused pad byte */ } xfs_attr_leaf_entry_t; typedef struct xfs_attr_leaf_name_local { __be16 valuelen; /* number of bytes in value */ __u8 namelen; /* length of name bytes */ __u8 nameval[1]; /* name/value bytes */ } xfs_attr_leaf_name_local_t; typedef struct xfs_attr_leaf_name_remote { __be32 valueblk; /* block number of value bytes */ __be32 valuelen; /* number of bytes in value */ __u8 namelen; /* length of name bytes */ __u8 name[1]; /* name bytes */ } xfs_attr_leaf_name_remote_t; typedef struct xfs_attr_leafblock { xfs_attr_leaf_hdr_t hdr; /* constant-structure header block */ xfs_attr_leaf_entry_t entries[1]; /* sorted on key, not name */ /* * The rest of the block contains the following structures after the * leaf entries, growing from the bottom up. The variables are never * referenced and definining them can actually make gcc optimize away * accesses to the 'entries' array above index 0 so don't do that. * * xfs_attr_leaf_name_local_t namelist; * xfs_attr_leaf_name_remote_t valuelist; */ } xfs_attr_leafblock_t; /* * CRC enabled leaf structures. Called "version 3" structures to match the * version number of the directory and dablk structures for this feature, and * attr2 is already taken by the variable inode attribute fork size feature. */ struct xfs_attr3_leaf_hdr { struct xfs_da3_blkinfo info; __be16 count; __be16 usedbytes; __be16 firstused; __u8 holes; __u8 pad1; struct xfs_attr_leaf_map freemap[XFS_ATTR_LEAF_MAPSIZE]; __be32 pad2; /* 64 bit alignment */ }; #define XFS_ATTR3_LEAF_CRC_OFF (offsetof(struct xfs_attr3_leaf_hdr, info.crc)) struct xfs_attr3_leafblock { struct xfs_attr3_leaf_hdr hdr; struct xfs_attr_leaf_entry entries[1]; /* * The rest of the block contains the following structures after the * leaf entries, growing from the bottom up. The variables are never * referenced, the locations accessed purely from helper functions. * * struct xfs_attr_leaf_name_local * struct xfs_attr_leaf_name_remote */ }; /* * incore, neutral version of the attribute leaf header */ struct xfs_attr3_icleaf_hdr { __uint32_t forw; __uint32_t back; __uint16_t magic; __uint16_t count; __uint16_t usedbytes; /* * firstused is 32-bit here instead of 16-bit like the on-disk variant * to support maximum fsb size of 64k without overflow issues throughout * the attr code. Instead, the overflow condition is handled on * conversion to/from disk. */ __uint32_t firstused; __u8 holes; struct { __uint16_t base; __uint16_t size; } freemap[XFS_ATTR_LEAF_MAPSIZE]; }; /* * Special value to represent fs block size in the leaf header firstused field. * Only used when block size overflows the 2-bytes available on disk. */ #define XFS_ATTR3_LEAF_NULLOFF 0 /* * Flags used in the leaf_entry[i].flags field. * NOTE: the INCOMPLETE bit must not collide with the flags bits specified * on the system call, they are "or"ed together for various operations. */ #define XFS_ATTR_LOCAL_BIT 0 /* attr is stored locally */ #define XFS_ATTR_ROOT_BIT 1 /* limit access to trusted attrs */ #define XFS_ATTR_SECURE_BIT 2 /* limit access to secure attrs */ #define XFS_ATTR_INCOMPLETE_BIT 7 /* attr in middle of create/delete */ #define XFS_ATTR_LOCAL (1 << XFS_ATTR_LOCAL_BIT) #define XFS_ATTR_ROOT (1 << XFS_ATTR_ROOT_BIT) #define XFS_ATTR_SECURE (1 << XFS_ATTR_SECURE_BIT) #define XFS_ATTR_INCOMPLETE (1 << XFS_ATTR_INCOMPLETE_BIT) /* * Conversion macros for converting namespace bits from argument flags * to ondisk flags. */ #define XFS_ATTR_NSP_ARGS_MASK (ATTR_ROOT | ATTR_SECURE) #define XFS_ATTR_NSP_ONDISK_MASK (XFS_ATTR_ROOT | XFS_ATTR_SECURE) #define XFS_ATTR_NSP_ONDISK(flags) ((flags) & XFS_ATTR_NSP_ONDISK_MASK) #define XFS_ATTR_NSP_ARGS(flags) ((flags) & XFS_ATTR_NSP_ARGS_MASK) #define XFS_ATTR_NSP_ARGS_TO_ONDISK(x) (((x) & ATTR_ROOT ? XFS_ATTR_ROOT : 0) |\ ((x) & ATTR_SECURE ? XFS_ATTR_SECURE : 0)) #define XFS_ATTR_NSP_ONDISK_TO_ARGS(x) (((x) & XFS_ATTR_ROOT ? ATTR_ROOT : 0) |\ ((x) & XFS_ATTR_SECURE ? ATTR_SECURE : 0)) /* * Alignment for namelist and valuelist entries (since they are mixed * there can be only one alignment value) */ #define XFS_ATTR_LEAF_NAME_ALIGN ((uint)sizeof(xfs_dablk_t)) static inline int xfs_attr3_leaf_hdr_size(struct xfs_attr_leafblock *leafp) { if (leafp->hdr.info.magic == cpu_to_be16(XFS_ATTR3_LEAF_MAGIC)) return sizeof(struct xfs_attr3_leaf_hdr); return sizeof(struct xfs_attr_leaf_hdr); } static inline struct xfs_attr_leaf_entry * xfs_attr3_leaf_entryp(xfs_attr_leafblock_t *leafp) { if (leafp->hdr.info.magic == cpu_to_be16(XFS_ATTR3_LEAF_MAGIC)) return &((struct xfs_attr3_leafblock *)leafp)->entries[0]; return &leafp->entries[0]; } /* * Cast typed pointers for "local" and "remote" name/value structs. */ static inline char * xfs_attr3_leaf_name(xfs_attr_leafblock_t *leafp, int idx) { struct xfs_attr_leaf_entry *entries = xfs_attr3_leaf_entryp(leafp); return &((char *)leafp)[be16_to_cpu(entries[idx].nameidx)]; } static inline xfs_attr_leaf_name_remote_t * xfs_attr3_leaf_name_remote(xfs_attr_leafblock_t *leafp, int idx) { return (xfs_attr_leaf_name_remote_t *)xfs_attr3_leaf_name(leafp, idx); } static inline xfs_attr_leaf_name_local_t * xfs_attr3_leaf_name_local(xfs_attr_leafblock_t *leafp, int idx) { return (xfs_attr_leaf_name_local_t *)xfs_attr3_leaf_name(leafp, idx); } /* * Calculate total bytes used (including trailing pad for alignment) for * a "local" name/value structure, a "remote" name/value structure, and * a pointer which might be either. */ static inline int xfs_attr_leaf_entsize_remote(int nlen) { return ((uint)sizeof(xfs_attr_leaf_name_remote_t) - 1 + (nlen) + \ XFS_ATTR_LEAF_NAME_ALIGN - 1) & ~(XFS_ATTR_LEAF_NAME_ALIGN - 1); } static inline int xfs_attr_leaf_entsize_local(int nlen, int vlen) { return ((uint)sizeof(xfs_attr_leaf_name_local_t) - 1 + (nlen) + (vlen) + XFS_ATTR_LEAF_NAME_ALIGN - 1) & ~(XFS_ATTR_LEAF_NAME_ALIGN - 1); } static inline int xfs_attr_leaf_entsize_local_max(int bsize) { return (((bsize) >> 1) + ((bsize) >> 2)); } /* * Remote attribute block format definition * * There is one of these headers per filesystem block in a remote attribute. * This is done to ensure there is a 1:1 mapping between the attribute value * length and the number of blocks needed to store the attribute. This makes the * verification of a buffer a little more complex, but greatly simplifies the * allocation, reading and writing of these attributes as we don't have to guess * the number of blocks needed to store the attribute data. */ #define XFS_ATTR3_RMT_MAGIC 0x5841524d /* XARM */ struct xfs_attr3_rmt_hdr { __be32 rm_magic; __be32 rm_offset; __be32 rm_bytes; __be32 rm_crc; uuid_t rm_uuid; __be64 rm_owner; __be64 rm_blkno; __be64 rm_lsn; }; #define XFS_ATTR3_RMT_CRC_OFF offsetof(struct xfs_attr3_rmt_hdr, rm_crc) #define XFS_ATTR3_RMT_BUF_SPACE(mp, bufsize) \ ((bufsize) - (xfs_sb_version_hascrc(&(mp)->m_sb) ? \ sizeof(struct xfs_attr3_rmt_hdr) : 0)) #endif /* __XFS_DA_FORMAT_H__ */ partclone-0.2.86/src/xfs/xfs_dir2.c000066400000000000000000000430111262102574200170510ustar00rootroot00000000000000/* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_mount.h" #include "xfs_da_format.h" #include "xfs_da_btree.h" #include "xfs_inode.h" #include "xfs_trans.h" #include "xfs_bmap.h" #include "xfs_dir2.h" #include "xfs_dir2_priv.h" #include "xfs_trace.h" struct xfs_name xfs_name_dotdot = { (unsigned char *)"..", 2, XFS_DIR3_FT_DIR }; /* * @mode, if set, indicates that the type field needs to be set up. * This uses the transformation from file mode to DT_* as defined in linux/fs.h * for file type specification. This will be propagated into the directory * structure if appropriate for the given operation and filesystem config. */ const unsigned char xfs_mode_to_ftype[S_IFMT >> S_SHIFT] = { [0] = XFS_DIR3_FT_UNKNOWN, [S_IFREG >> S_SHIFT] = XFS_DIR3_FT_REG_FILE, [S_IFDIR >> S_SHIFT] = XFS_DIR3_FT_DIR, [S_IFCHR >> S_SHIFT] = XFS_DIR3_FT_CHRDEV, [S_IFBLK >> S_SHIFT] = XFS_DIR3_FT_BLKDEV, [S_IFIFO >> S_SHIFT] = XFS_DIR3_FT_FIFO, [S_IFSOCK >> S_SHIFT] = XFS_DIR3_FT_SOCK, [S_IFLNK >> S_SHIFT] = XFS_DIR3_FT_SYMLINK, }; /* * ASCII case-insensitive (ie. A-Z) support for directories that was * used in IRIX. */ STATIC xfs_dahash_t xfs_ascii_ci_hashname( struct xfs_name *name) { xfs_dahash_t hash; int i; for (i = 0, hash = 0; i < name->len; i++) hash = tolower(name->name[i]) ^ rol32(hash, 7); return hash; } STATIC enum xfs_dacmp xfs_ascii_ci_compname( struct xfs_da_args *args, const unsigned char *name, int len) { enum xfs_dacmp result; int i; if (args->namelen != len) return XFS_CMP_DIFFERENT; result = XFS_CMP_EXACT; for (i = 0; i < len; i++) { if (args->name[i] == name[i]) continue; if (tolower(args->name[i]) != tolower(name[i])) return XFS_CMP_DIFFERENT; result = XFS_CMP_CASE; } return result; } static struct xfs_nameops xfs_ascii_ci_nameops = { .hashname = xfs_ascii_ci_hashname, .compname = xfs_ascii_ci_compname, }; int xfs_da_mount( struct xfs_mount *mp) { struct xfs_da_geometry *dageo; int nodehdr_size; ASSERT(mp->m_sb.sb_versionnum & XFS_SB_VERSION_DIRV2BIT); ASSERT((1 << (mp->m_sb.sb_blocklog + mp->m_sb.sb_dirblklog)) <= XFS_MAX_BLOCKSIZE); mp->m_dir_inode_ops = xfs_dir_get_ops(mp, NULL); mp->m_nondir_inode_ops = xfs_nondir_get_ops(mp, NULL); nodehdr_size = mp->m_dir_inode_ops->node_hdr_size; mp->m_dir_geo = kmem_zalloc(sizeof(struct xfs_da_geometry), KM_SLEEP | KM_MAYFAIL); mp->m_attr_geo = kmem_zalloc(sizeof(struct xfs_da_geometry), KM_SLEEP | KM_MAYFAIL); if (!mp->m_dir_geo || !mp->m_attr_geo) { kmem_free(mp->m_dir_geo); kmem_free(mp->m_attr_geo); return -ENOMEM; } /* set up directory geometry */ dageo = mp->m_dir_geo; dageo->blklog = mp->m_sb.sb_blocklog + mp->m_sb.sb_dirblklog; dageo->fsblog = mp->m_sb.sb_blocklog; dageo->blksize = 1 << dageo->blklog; dageo->fsbcount = 1 << mp->m_sb.sb_dirblklog; /* * Now we've set up the block conversion variables, we can calculate the * segment block constants using the geometry structure. */ dageo->datablk = xfs_dir2_byte_to_da(dageo, XFS_DIR2_DATA_OFFSET); dageo->leafblk = xfs_dir2_byte_to_da(dageo, XFS_DIR2_LEAF_OFFSET); dageo->freeblk = xfs_dir2_byte_to_da(dageo, XFS_DIR2_FREE_OFFSET); dageo->node_ents = (dageo->blksize - nodehdr_size) / (uint)sizeof(xfs_da_node_entry_t); dageo->magicpct = (dageo->blksize * 37) / 100; /* set up attribute geometry - single fsb only */ dageo = mp->m_attr_geo; dageo->blklog = mp->m_sb.sb_blocklog; dageo->fsblog = mp->m_sb.sb_blocklog; dageo->blksize = 1 << dageo->blklog; dageo->fsbcount = 1; dageo->node_ents = (dageo->blksize - nodehdr_size) / (uint)sizeof(xfs_da_node_entry_t); dageo->magicpct = (dageo->blksize * 37) / 100; if (xfs_sb_version_hasasciici(&mp->m_sb)) mp->m_dirnameops = &xfs_ascii_ci_nameops; else mp->m_dirnameops = &xfs_default_nameops; return 0; } void xfs_da_unmount( struct xfs_mount *mp) { kmem_free(mp->m_dir_geo); kmem_free(mp->m_attr_geo); } /* * Return 1 if directory contains only "." and "..". */ int xfs_dir_isempty( xfs_inode_t *dp) { xfs_dir2_sf_hdr_t *sfp; ASSERT(S_ISDIR(dp->i_d.di_mode)); if (dp->i_d.di_size == 0) /* might happen during shutdown. */ return 1; if (dp->i_d.di_size > XFS_IFORK_DSIZE(dp)) return 0; sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; return !sfp->count; } /* * Validate a given inode number. */ int xfs_dir_ino_validate( xfs_mount_t *mp, xfs_ino_t ino) { xfs_agblock_t agblkno; xfs_agino_t agino; xfs_agnumber_t agno; int ino_ok; int ioff; agno = XFS_INO_TO_AGNO(mp, ino); agblkno = XFS_INO_TO_AGBNO(mp, ino); ioff = XFS_INO_TO_OFFSET(mp, ino); agino = XFS_OFFBNO_TO_AGINO(mp, agblkno, ioff); ino_ok = agno < mp->m_sb.sb_agcount && agblkno < mp->m_sb.sb_agblocks && agblkno != 0 && ioff < (1 << mp->m_sb.sb_inopblog) && XFS_AGINO_TO_INO(mp, agno, agino) == ino; if (unlikely(XFS_TEST_ERROR(!ino_ok, mp, XFS_ERRTAG_DIR_INO_VALIDATE, XFS_RANDOM_DIR_INO_VALIDATE))) { xfs_warn(mp, "Invalid inode number 0x%Lx", (unsigned long long) ino); XFS_ERROR_REPORT("xfs_dir_ino_validate", XFS_ERRLEVEL_LOW, mp); return -EFSCORRUPTED; } return 0; } /* * Initialize a directory with its "." and ".." entries. */ int xfs_dir_init( xfs_trans_t *tp, xfs_inode_t *dp, xfs_inode_t *pdp) { struct xfs_da_args *args; int error; ASSERT(S_ISDIR(dp->i_d.di_mode)); error = xfs_dir_ino_validate(tp->t_mountp, pdp->i_ino); if (error) return error; args = kmem_zalloc(sizeof(*args), KM_SLEEP | KM_NOFS); if (!args) return -ENOMEM; args->geo = dp->i_mount->m_dir_geo; args->dp = dp; args->trans = tp; error = xfs_dir2_sf_create(args, pdp->i_ino); kmem_free(args); return error; } /* * Enter a name in a directory, or check for available space. * If inum is 0, only the available space test is performed. */ int xfs_dir_createname( xfs_trans_t *tp, xfs_inode_t *dp, struct xfs_name *name, xfs_ino_t inum, /* new entry inode number */ xfs_fsblock_t *first, /* bmap's firstblock */ xfs_bmap_free_t *flist, /* bmap's freeblock list */ xfs_extlen_t total) /* bmap's total block count */ { struct xfs_da_args *args; int rval; int v; /* type-checking value */ ASSERT(S_ISDIR(dp->i_d.di_mode)); if (inum) { rval = xfs_dir_ino_validate(tp->t_mountp, inum); if (rval) return rval; XFS_STATS_INC(xs_dir_create); } args = kmem_zalloc(sizeof(*args), KM_SLEEP | KM_NOFS); if (!args) return -ENOMEM; args->geo = dp->i_mount->m_dir_geo; args->name = name->name; args->namelen = name->len; args->filetype = name->type; args->hashval = dp->i_mount->m_dirnameops->hashname(name); args->inumber = inum; args->dp = dp; args->firstblock = first; args->flist = flist; args->total = total; args->whichfork = XFS_DATA_FORK; args->trans = tp; args->op_flags = XFS_DA_OP_ADDNAME | XFS_DA_OP_OKNOENT; if (!inum) args->op_flags |= XFS_DA_OP_JUSTCHECK; if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) { rval = xfs_dir2_sf_addname(args); goto out_free; } rval = xfs_dir2_isblock(args, &v); if (rval) goto out_free; if (v) { rval = xfs_dir2_block_addname(args); goto out_free; } rval = xfs_dir2_isleaf(args, &v); if (rval) goto out_free; if (v) rval = xfs_dir2_leaf_addname(args); else rval = xfs_dir2_node_addname(args); out_free: kmem_free(args); return rval; } /* * If doing a CI lookup and case-insensitive match, dup actual name into * args.value. Return EEXIST for success (ie. name found) or an error. */ int xfs_dir_cilookup_result( struct xfs_da_args *args, const unsigned char *name, int len) { if (args->cmpresult == XFS_CMP_DIFFERENT) return -ENOENT; if (args->cmpresult != XFS_CMP_CASE || !(args->op_flags & XFS_DA_OP_CILOOKUP)) return -EEXIST; args->value = kmem_alloc(len, KM_NOFS | KM_MAYFAIL); if (!args->value) return -ENOMEM; memcpy(args->value, name, len); args->valuelen = len; return -EEXIST; } /* * Lookup a name in a directory, give back the inode number. * If ci_name is not NULL, returns the actual name in ci_name if it differs * to name, or ci_name->name is set to NULL for an exact match. */ int xfs_dir_lookup( xfs_trans_t *tp, xfs_inode_t *dp, struct xfs_name *name, xfs_ino_t *inum, /* out: inode number */ struct xfs_name *ci_name) /* out: actual name if CI match */ { struct xfs_da_args *args; int rval; int v; /* type-checking value */ ASSERT(S_ISDIR(dp->i_d.di_mode)); XFS_STATS_INC(xs_dir_lookup); /* * We need to use KM_NOFS here so that lockdep will not throw false * positive deadlock warnings on a non-transactional lookup path. It is * safe to recurse into inode recalim in that case, but lockdep can't * easily be taught about it. Hence KM_NOFS avoids having to add more * lockdep Doing this avoids having to add a bunch of lockdep class * annotations into the reclaim path for the ilock. */ args = kmem_zalloc(sizeof(*args), KM_SLEEP | KM_NOFS); args->geo = dp->i_mount->m_dir_geo; args->name = name->name; args->namelen = name->len; args->filetype = name->type; args->hashval = dp->i_mount->m_dirnameops->hashname(name); args->dp = dp; args->whichfork = XFS_DATA_FORK; args->trans = tp; args->op_flags = XFS_DA_OP_OKNOENT; if (ci_name) args->op_flags |= XFS_DA_OP_CILOOKUP; if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) { rval = xfs_dir2_sf_lookup(args); goto out_check_rval; } rval = xfs_dir2_isblock(args, &v); if (rval) goto out_free; if (v) { rval = xfs_dir2_block_lookup(args); goto out_check_rval; } rval = xfs_dir2_isleaf(args, &v); if (rval) goto out_free; if (v) rval = xfs_dir2_leaf_lookup(args); else rval = xfs_dir2_node_lookup(args); out_check_rval: if (rval == -EEXIST) rval = 0; if (!rval) { *inum = args->inumber; if (ci_name) { ci_name->name = args->value; ci_name->len = args->valuelen; } } out_free: kmem_free(args); return rval; } /* * Remove an entry from a directory. */ int xfs_dir_removename( xfs_trans_t *tp, xfs_inode_t *dp, struct xfs_name *name, xfs_ino_t ino, xfs_fsblock_t *first, /* bmap's firstblock */ xfs_bmap_free_t *flist, /* bmap's freeblock list */ xfs_extlen_t total) /* bmap's total block count */ { struct xfs_da_args *args; int rval; int v; /* type-checking value */ ASSERT(S_ISDIR(dp->i_d.di_mode)); XFS_STATS_INC(xs_dir_remove); args = kmem_zalloc(sizeof(*args), KM_SLEEP | KM_NOFS); if (!args) return -ENOMEM; args->geo = dp->i_mount->m_dir_geo; args->name = name->name; args->namelen = name->len; args->filetype = name->type; args->hashval = dp->i_mount->m_dirnameops->hashname(name); args->inumber = ino; args->dp = dp; args->firstblock = first; args->flist = flist; args->total = total; args->whichfork = XFS_DATA_FORK; args->trans = tp; if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) { rval = xfs_dir2_sf_removename(args); goto out_free; } rval = xfs_dir2_isblock(args, &v); if (rval) goto out_free; if (v) { rval = xfs_dir2_block_removename(args); goto out_free; } rval = xfs_dir2_isleaf(args, &v); if (rval) goto out_free; if (v) rval = xfs_dir2_leaf_removename(args); else rval = xfs_dir2_node_removename(args); out_free: kmem_free(args); return rval; } /* * Replace the inode number of a directory entry. */ int xfs_dir_replace( xfs_trans_t *tp, xfs_inode_t *dp, struct xfs_name *name, /* name of entry to replace */ xfs_ino_t inum, /* new inode number */ xfs_fsblock_t *first, /* bmap's firstblock */ xfs_bmap_free_t *flist, /* bmap's freeblock list */ xfs_extlen_t total) /* bmap's total block count */ { struct xfs_da_args *args; int rval; int v; /* type-checking value */ ASSERT(S_ISDIR(dp->i_d.di_mode)); rval = xfs_dir_ino_validate(tp->t_mountp, inum); if (rval) return rval; args = kmem_zalloc(sizeof(*args), KM_SLEEP | KM_NOFS); if (!args) return -ENOMEM; args->geo = dp->i_mount->m_dir_geo; args->name = name->name; args->namelen = name->len; args->filetype = name->type; args->hashval = dp->i_mount->m_dirnameops->hashname(name); args->inumber = inum; args->dp = dp; args->firstblock = first; args->flist = flist; args->total = total; args->whichfork = XFS_DATA_FORK; args->trans = tp; if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) { rval = xfs_dir2_sf_replace(args); goto out_free; } rval = xfs_dir2_isblock(args, &v); if (rval) goto out_free; if (v) { rval = xfs_dir2_block_replace(args); goto out_free; } rval = xfs_dir2_isleaf(args, &v); if (rval) goto out_free; if (v) rval = xfs_dir2_leaf_replace(args); else rval = xfs_dir2_node_replace(args); out_free: kmem_free(args); return rval; } /* * See if this entry can be added to the directory without allocating space. */ int xfs_dir_canenter( xfs_trans_t *tp, xfs_inode_t *dp, struct xfs_name *name) /* name of entry to add */ { return xfs_dir_createname(tp, dp, name, 0, NULL, NULL, 0); } /* * Utility routines. */ /* * Add a block to the directory. * * This routine is for data and free blocks, not leaf/node blocks which are * handled by xfs_da_grow_inode. */ int xfs_dir2_grow_inode( struct xfs_da_args *args, int space, /* v2 dir's space XFS_DIR2_xxx_SPACE */ xfs_dir2_db_t *dbp) /* out: block number added */ { struct xfs_inode *dp = args->dp; struct xfs_mount *mp = dp->i_mount; xfs_fileoff_t bno; /* directory offset of new block */ int count; /* count of filesystem blocks */ int error; trace_xfs_dir2_grow_inode(args, space); /* * Set lowest possible block in the space requested. */ bno = XFS_B_TO_FSBT(mp, space * XFS_DIR2_SPACE_SIZE); count = args->geo->fsbcount; error = xfs_da_grow_inode_int(args, &bno, count); if (error) return error; *dbp = xfs_dir2_da_to_db(args->geo, (xfs_dablk_t)bno); /* * Update file's size if this is the data space and it grew. */ if (space == XFS_DIR2_DATA_SPACE) { xfs_fsize_t size; /* directory file (data) size */ size = XFS_FSB_TO_B(mp, bno + count); if (size > dp->i_d.di_size) { dp->i_d.di_size = size; xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE); } } return 0; } /* * See if the directory is a single-block form directory. */ int xfs_dir2_isblock( struct xfs_da_args *args, int *vp) /* out: 1 is block, 0 is not block */ { xfs_fileoff_t last; /* last file offset */ int rval; if ((rval = xfs_bmap_last_offset(args->dp, &last, XFS_DATA_FORK))) return rval; rval = XFS_FSB_TO_B(args->dp->i_mount, last) == args->geo->blksize; ASSERT(rval == 0 || args->dp->i_d.di_size == args->geo->blksize); *vp = rval; return 0; } /* * See if the directory is a single-leaf form directory. */ int xfs_dir2_isleaf( struct xfs_da_args *args, int *vp) /* out: 1 is block, 0 is not block */ { xfs_fileoff_t last; /* last file offset */ int rval; if ((rval = xfs_bmap_last_offset(args->dp, &last, XFS_DATA_FORK))) return rval; *vp = last == args->geo->leafblk + args->geo->fsbcount; return 0; } /* * Remove the given block from the directory. * This routine is used for data and free blocks, leaf/node are done * by xfs_da_shrink_inode. */ int xfs_dir2_shrink_inode( xfs_da_args_t *args, xfs_dir2_db_t db, struct xfs_buf *bp) { xfs_fileoff_t bno; /* directory file offset */ xfs_dablk_t da; /* directory file offset */ int done; /* bunmap is finished */ xfs_inode_t *dp; int error; xfs_mount_t *mp; xfs_trans_t *tp; trace_xfs_dir2_shrink_inode(args, db); dp = args->dp; mp = dp->i_mount; tp = args->trans; da = xfs_dir2_db_to_da(args->geo, db); /* Unmap the fsblock(s). */ error = xfs_bunmapi(tp, dp, da, args->geo->fsbcount, 0, 0, args->firstblock, args->flist, &done); if (error) { /* * ENOSPC actually can happen if we're in a removename with no * space reservation, and the resulting block removal would * cause a bmap btree split or conversion from extents to btree. * This can only happen for un-fragmented directory blocks, * since you need to be punching out the middle of an extent. * In this case we need to leave the block in the file, and not * binval it. So the block has to be in a consistent empty * state and appropriately logged. We don't free up the buffer, * the caller can tell it hasn't happened since it got an error * back. */ return error; } ASSERT(done); /* * Invalidate the buffer from the transaction. */ xfs_trans_binval(tp, bp); /* * If it's not a data block, we're done. */ if (db >= xfs_dir2_byte_to_db(args->geo, XFS_DIR2_LEAF_OFFSET)) return 0; /* * If the block isn't the last one in the directory, we're done. */ if (dp->i_d.di_size > xfs_dir2_db_off_to_byte(args->geo, db + 1, 0)) return 0; bno = da; if ((error = xfs_bmap_last_before(tp, dp, &bno, XFS_DATA_FORK))) { /* * This can't really happen unless there's kernel corruption. */ return error; } if (db == args->geo->datablk) ASSERT(bno == 0); else ASSERT(bno > 0); /* * Set the size to the new last block. */ dp->i_d.di_size = XFS_FSB_TO_B(mp, bno); xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE); return 0; } partclone-0.2.86/src/xfs/xfs_dir2.h000066400000000000000000000241151262102574200170620ustar00rootroot00000000000000/* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __XFS_DIR2_H__ #define __XFS_DIR2_H__ struct xfs_bmap_free; struct xfs_da_args; struct xfs_inode; struct xfs_mount; struct xfs_trans; struct xfs_dir2_sf_hdr; struct xfs_dir2_sf_entry; struct xfs_dir2_data_hdr; struct xfs_dir2_data_entry; struct xfs_dir2_data_unused; extern struct xfs_name xfs_name_dotdot; /* * directory filetype conversion tables. */ #define S_SHIFT 12 extern const unsigned char xfs_mode_to_ftype[]; /* * directory operations vector for encode/decode routines */ struct xfs_dir_ops { int (*sf_entsize)(struct xfs_dir2_sf_hdr *hdr, int len); struct xfs_dir2_sf_entry * (*sf_nextentry)(struct xfs_dir2_sf_hdr *hdr, struct xfs_dir2_sf_entry *sfep); __uint8_t (*sf_get_ftype)(struct xfs_dir2_sf_entry *sfep); void (*sf_put_ftype)(struct xfs_dir2_sf_entry *sfep, __uint8_t ftype); xfs_ino_t (*sf_get_ino)(struct xfs_dir2_sf_hdr *hdr, struct xfs_dir2_sf_entry *sfep); void (*sf_put_ino)(struct xfs_dir2_sf_hdr *hdr, struct xfs_dir2_sf_entry *sfep, xfs_ino_t ino); xfs_ino_t (*sf_get_parent_ino)(struct xfs_dir2_sf_hdr *hdr); void (*sf_put_parent_ino)(struct xfs_dir2_sf_hdr *hdr, xfs_ino_t ino); int (*data_entsize)(int len); __uint8_t (*data_get_ftype)(struct xfs_dir2_data_entry *dep); void (*data_put_ftype)(struct xfs_dir2_data_entry *dep, __uint8_t ftype); __be16 * (*data_entry_tag_p)(struct xfs_dir2_data_entry *dep); struct xfs_dir2_data_free * (*data_bestfree_p)(struct xfs_dir2_data_hdr *hdr); xfs_dir2_data_aoff_t data_dot_offset; xfs_dir2_data_aoff_t data_dotdot_offset; xfs_dir2_data_aoff_t data_first_offset; size_t data_entry_offset; struct xfs_dir2_data_entry * (*data_dot_entry_p)(struct xfs_dir2_data_hdr *hdr); struct xfs_dir2_data_entry * (*data_dotdot_entry_p)(struct xfs_dir2_data_hdr *hdr); struct xfs_dir2_data_entry * (*data_first_entry_p)(struct xfs_dir2_data_hdr *hdr); struct xfs_dir2_data_entry * (*data_entry_p)(struct xfs_dir2_data_hdr *hdr); struct xfs_dir2_data_unused * (*data_unused_p)(struct xfs_dir2_data_hdr *hdr); int leaf_hdr_size; void (*leaf_hdr_to_disk)(struct xfs_dir2_leaf *to, struct xfs_dir3_icleaf_hdr *from); void (*leaf_hdr_from_disk)(struct xfs_dir3_icleaf_hdr *to, struct xfs_dir2_leaf *from); int (*leaf_max_ents)(struct xfs_da_geometry *geo); struct xfs_dir2_leaf_entry * (*leaf_ents_p)(struct xfs_dir2_leaf *lp); int node_hdr_size; void (*node_hdr_to_disk)(struct xfs_da_intnode *to, struct xfs_da3_icnode_hdr *from); void (*node_hdr_from_disk)(struct xfs_da3_icnode_hdr *to, struct xfs_da_intnode *from); struct xfs_da_node_entry * (*node_tree_p)(struct xfs_da_intnode *dap); int free_hdr_size; void (*free_hdr_to_disk)(struct xfs_dir2_free *to, struct xfs_dir3_icfree_hdr *from); void (*free_hdr_from_disk)(struct xfs_dir3_icfree_hdr *to, struct xfs_dir2_free *from); int (*free_max_bests)(struct xfs_da_geometry *geo); __be16 * (*free_bests_p)(struct xfs_dir2_free *free); xfs_dir2_db_t (*db_to_fdb)(struct xfs_da_geometry *geo, xfs_dir2_db_t db); int (*db_to_fdindex)(struct xfs_da_geometry *geo, xfs_dir2_db_t db); }; extern const struct xfs_dir_ops * xfs_dir_get_ops(struct xfs_mount *mp, struct xfs_inode *dp); extern const struct xfs_dir_ops * xfs_nondir_get_ops(struct xfs_mount *mp, struct xfs_inode *dp); /* * Generic directory interface routines */ extern void xfs_dir_startup(void); extern int xfs_da_mount(struct xfs_mount *mp); extern void xfs_da_unmount(struct xfs_mount *mp); extern int xfs_dir_isempty(struct xfs_inode *dp); extern int xfs_dir_init(struct xfs_trans *tp, struct xfs_inode *dp, struct xfs_inode *pdp); extern int xfs_dir_createname(struct xfs_trans *tp, struct xfs_inode *dp, struct xfs_name *name, xfs_ino_t inum, xfs_fsblock_t *first, struct xfs_bmap_free *flist, xfs_extlen_t tot); extern int xfs_dir_lookup(struct xfs_trans *tp, struct xfs_inode *dp, struct xfs_name *name, xfs_ino_t *inum, struct xfs_name *ci_name); extern int xfs_dir_removename(struct xfs_trans *tp, struct xfs_inode *dp, struct xfs_name *name, xfs_ino_t ino, xfs_fsblock_t *first, struct xfs_bmap_free *flist, xfs_extlen_t tot); extern int xfs_dir_replace(struct xfs_trans *tp, struct xfs_inode *dp, struct xfs_name *name, xfs_ino_t inum, xfs_fsblock_t *first, struct xfs_bmap_free *flist, xfs_extlen_t tot); extern int xfs_dir_canenter(struct xfs_trans *tp, struct xfs_inode *dp, struct xfs_name *name); /* * Direct call from the bmap code, bypassing the generic directory layer. */ extern int xfs_dir2_sf_to_block(struct xfs_da_args *args); /* * Interface routines used by userspace utilities */ extern int xfs_dir2_isblock(struct xfs_da_args *args, int *r); extern int xfs_dir2_isleaf(struct xfs_da_args *args, int *r); extern int xfs_dir2_shrink_inode(struct xfs_da_args *args, xfs_dir2_db_t db, struct xfs_buf *bp); extern void __xfs_dir2_data_freescan(struct xfs_da_geometry *geo, const struct xfs_dir_ops *ops, struct xfs_dir2_data_hdr *hdr, int *loghead); extern void xfs_dir2_data_log_entry(struct xfs_da_args *args, struct xfs_buf *bp, struct xfs_dir2_data_entry *dep); extern void xfs_dir2_data_log_header(struct xfs_da_args *args, struct xfs_buf *bp); extern void xfs_dir2_data_log_unused(struct xfs_da_args *args, struct xfs_buf *bp, struct xfs_dir2_data_unused *dup); extern void xfs_dir2_data_make_free(struct xfs_da_args *args, struct xfs_buf *bp, xfs_dir2_data_aoff_t offset, xfs_dir2_data_aoff_t len, int *needlogp, int *needscanp); extern void xfs_dir2_data_use_free(struct xfs_da_args *args, struct xfs_buf *bp, struct xfs_dir2_data_unused *dup, xfs_dir2_data_aoff_t offset, xfs_dir2_data_aoff_t len, int *needlogp, int *needscanp); extern struct xfs_dir2_data_free *xfs_dir2_data_freefind( struct xfs_dir2_data_hdr *hdr, struct xfs_dir2_data_free *bf, struct xfs_dir2_data_unused *dup); extern int xfs_dir_ino_validate(struct xfs_mount *mp, xfs_ino_t ino); extern const struct xfs_buf_ops xfs_dir3_block_buf_ops; extern const struct xfs_buf_ops xfs_dir3_leafn_buf_ops; extern const struct xfs_buf_ops xfs_dir3_leaf1_buf_ops; extern const struct xfs_buf_ops xfs_dir3_free_buf_ops; extern const struct xfs_buf_ops xfs_dir3_data_buf_ops; /* * Directory offset/block conversion functions. * * DB blocks here are logical directory block numbers, not filesystem blocks. */ /* * Convert dataptr to byte in file space */ static inline xfs_dir2_off_t xfs_dir2_dataptr_to_byte(xfs_dir2_dataptr_t dp) { return (xfs_dir2_off_t)dp << XFS_DIR2_DATA_ALIGN_LOG; } /* * Convert byte in file space to dataptr. It had better be aligned. */ static inline xfs_dir2_dataptr_t xfs_dir2_byte_to_dataptr(xfs_dir2_off_t by) { return (xfs_dir2_dataptr_t)(by >> XFS_DIR2_DATA_ALIGN_LOG); } /* * Convert byte in space to (DB) block */ static inline xfs_dir2_db_t xfs_dir2_byte_to_db(struct xfs_da_geometry *geo, xfs_dir2_off_t by) { return (xfs_dir2_db_t)(by >> geo->blklog); } /* * Convert dataptr to a block number */ static inline xfs_dir2_db_t xfs_dir2_dataptr_to_db(struct xfs_da_geometry *geo, xfs_dir2_dataptr_t dp) { return xfs_dir2_byte_to_db(geo, xfs_dir2_dataptr_to_byte(dp)); } /* * Convert byte in space to offset in a block */ static inline xfs_dir2_data_aoff_t xfs_dir2_byte_to_off(struct xfs_da_geometry *geo, xfs_dir2_off_t by) { return (xfs_dir2_data_aoff_t)(by & (geo->blksize - 1)); } /* * Convert dataptr to a byte offset in a block */ static inline xfs_dir2_data_aoff_t xfs_dir2_dataptr_to_off(struct xfs_da_geometry *geo, xfs_dir2_dataptr_t dp) { return xfs_dir2_byte_to_off(geo, xfs_dir2_dataptr_to_byte(dp)); } /* * Convert block and offset to byte in space */ static inline xfs_dir2_off_t xfs_dir2_db_off_to_byte(struct xfs_da_geometry *geo, xfs_dir2_db_t db, xfs_dir2_data_aoff_t o) { return ((xfs_dir2_off_t)db << geo->blklog) + o; } /* * Convert block (DB) to block (dablk) */ static inline xfs_dablk_t xfs_dir2_db_to_da(struct xfs_da_geometry *geo, xfs_dir2_db_t db) { return (xfs_dablk_t)(db << (geo->blklog - geo->fsblog)); } /* * Convert byte in space to (DA) block */ static inline xfs_dablk_t xfs_dir2_byte_to_da(struct xfs_da_geometry *geo, xfs_dir2_off_t by) { return xfs_dir2_db_to_da(geo, xfs_dir2_byte_to_db(geo, by)); } /* * Convert block and offset to dataptr */ static inline xfs_dir2_dataptr_t xfs_dir2_db_off_to_dataptr(struct xfs_da_geometry *geo, xfs_dir2_db_t db, xfs_dir2_data_aoff_t o) { return xfs_dir2_byte_to_dataptr(xfs_dir2_db_off_to_byte(geo, db, o)); } /* * Convert block (dablk) to block (DB) */ static inline xfs_dir2_db_t xfs_dir2_da_to_db(struct xfs_da_geometry *geo, xfs_dablk_t da) { return (xfs_dir2_db_t)(da >> (geo->blklog - geo->fsblog)); } /* * Convert block (dablk) to byte offset in space */ static inline xfs_dir2_off_t xfs_dir2_da_to_byte(struct xfs_da_geometry *geo, xfs_dablk_t da) { return xfs_dir2_db_off_to_byte(geo, xfs_dir2_da_to_db(geo, da), 0); } /* * Directory tail pointer accessor functions. Based on block geometry. */ static inline struct xfs_dir2_block_tail * xfs_dir2_block_tail_p(struct xfs_da_geometry *geo, struct xfs_dir2_data_hdr *hdr) { return ((struct xfs_dir2_block_tail *) ((char *)hdr + geo->blksize)) - 1; } static inline struct xfs_dir2_leaf_tail * xfs_dir2_leaf_tail_p(struct xfs_da_geometry *geo, struct xfs_dir2_leaf *lp) { return (struct xfs_dir2_leaf_tail *) ((char *)lp + geo->blksize - sizeof(struct xfs_dir2_leaf_tail)); } #endif /* __XFS_DIR2_H__ */ partclone-0.2.86/src/xfs/xfs_dir2_block.c000066400000000000000000001057221262102574200202330ustar00rootroot00000000000000/* * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. * Copyright (c) 2013 Red Hat, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_mount.h" #include "xfs_da_format.h" #include "xfs_da_btree.h" #include "xfs_inode.h" #include "xfs_trans.h" #include "xfs_bmap.h" #include "xfs_dir2.h" #include "xfs_dir2_priv.h" #include "xfs_trace.h" #include "xfs_cksum.h" /* * Local function prototypes. */ static void xfs_dir2_block_log_leaf(xfs_trans_t *tp, struct xfs_buf *bp, int first, int last); static void xfs_dir2_block_log_tail(xfs_trans_t *tp, struct xfs_buf *bp); static int xfs_dir2_block_lookup_int(xfs_da_args_t *args, struct xfs_buf **bpp, int *entno); static int xfs_dir2_block_sort(const void *a, const void *b); static xfs_dahash_t xfs_dir_hash_dot, xfs_dir_hash_dotdot; /* * One-time startup routine called from xfs_init(). */ void xfs_dir_startup(void) { xfs_dir_hash_dot = xfs_da_hashname((unsigned char *)".", 1); xfs_dir_hash_dotdot = xfs_da_hashname((unsigned char *)"..", 2); } static bool xfs_dir3_block_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_target->bt_mount; struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr; if (xfs_sb_version_hascrc(&mp->m_sb)) { if (hdr3->magic != cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)) return false; if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_meta_uuid)) return false; if (be64_to_cpu(hdr3->blkno) != bp->b_bn) return false; } else { if (hdr3->magic != cpu_to_be32(XFS_DIR2_BLOCK_MAGIC)) return false; } if (__xfs_dir3_data_check(NULL, bp)) return false; return true; } static void xfs_dir3_block_read_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_target->bt_mount; if (xfs_sb_version_hascrc(&mp->m_sb) && !xfs_buf_verify_cksum(bp, XFS_DIR3_DATA_CRC_OFF)) xfs_buf_ioerror(bp, -EFSBADCRC); else if (!xfs_dir3_block_verify(bp)) xfs_buf_ioerror(bp, -EFSCORRUPTED); if (bp->b_error) xfs_verifier_error(bp); } static void xfs_dir3_block_write_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_target->bt_mount; struct xfs_buf_log_item *bip = bp->b_fspriv; struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr; if (!xfs_dir3_block_verify(bp)) { xfs_buf_ioerror(bp, -EFSCORRUPTED); xfs_verifier_error(bp); return; } if (!xfs_sb_version_hascrc(&mp->m_sb)) return; if (bip) hdr3->lsn = cpu_to_be64(bip->bli_item.li_lsn); xfs_buf_update_cksum(bp, XFS_DIR3_DATA_CRC_OFF); } const struct xfs_buf_ops xfs_dir3_block_buf_ops = { .verify_read = xfs_dir3_block_read_verify, .verify_write = xfs_dir3_block_write_verify, }; int xfs_dir3_block_read( struct xfs_trans *tp, struct xfs_inode *dp, struct xfs_buf **bpp) { struct xfs_mount *mp = dp->i_mount; int err; err = xfs_da_read_buf(tp, dp, mp->m_dir_geo->datablk, -1, bpp, XFS_DATA_FORK, &xfs_dir3_block_buf_ops); if (!err && tp) xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_DIR_BLOCK_BUF); return err; } static void xfs_dir3_block_init( struct xfs_mount *mp, struct xfs_trans *tp, struct xfs_buf *bp, struct xfs_inode *dp) { struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr; bp->b_ops = &xfs_dir3_block_buf_ops; xfs_trans_buf_set_type(tp, bp, XFS_BLFT_DIR_BLOCK_BUF); if (xfs_sb_version_hascrc(&mp->m_sb)) { memset(hdr3, 0, sizeof(*hdr3)); hdr3->magic = cpu_to_be32(XFS_DIR3_BLOCK_MAGIC); hdr3->blkno = cpu_to_be64(bp->b_bn); hdr3->owner = cpu_to_be64(dp->i_ino); uuid_copy(&hdr3->uuid, &mp->m_sb.sb_meta_uuid); return; } hdr3->magic = cpu_to_be32(XFS_DIR2_BLOCK_MAGIC); } static void xfs_dir2_block_need_space( struct xfs_inode *dp, struct xfs_dir2_data_hdr *hdr, struct xfs_dir2_block_tail *btp, struct xfs_dir2_leaf_entry *blp, __be16 **tagpp, struct xfs_dir2_data_unused **dupp, struct xfs_dir2_data_unused **enddupp, int *compact, int len) { struct xfs_dir2_data_free *bf; __be16 *tagp = NULL; struct xfs_dir2_data_unused *dup = NULL; struct xfs_dir2_data_unused *enddup = NULL; *compact = 0; bf = dp->d_ops->data_bestfree_p(hdr); /* * If there are stale entries we'll use one for the leaf. */ if (btp->stale) { if (be16_to_cpu(bf[0].length) >= len) { /* * The biggest entry enough to avoid compaction. */ dup = (xfs_dir2_data_unused_t *) ((char *)hdr + be16_to_cpu(bf[0].offset)); goto out; } /* * Will need to compact to make this work. * Tag just before the first leaf entry. */ *compact = 1; tagp = (__be16 *)blp - 1; /* Data object just before the first leaf entry. */ dup = (xfs_dir2_data_unused_t *)((char *)hdr + be16_to_cpu(*tagp)); /* * If it's not free then the data will go where the * leaf data starts now, if it works at all. */ if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) { if (be16_to_cpu(dup->length) + (be32_to_cpu(btp->stale) - 1) * (uint)sizeof(*blp) < len) dup = NULL; } else if ((be32_to_cpu(btp->stale) - 1) * (uint)sizeof(*blp) < len) dup = NULL; else dup = (xfs_dir2_data_unused_t *)blp; goto out; } /* * no stale entries, so just use free space. * Tag just before the first leaf entry. */ tagp = (__be16 *)blp - 1; /* Data object just before the first leaf entry. */ enddup = (xfs_dir2_data_unused_t *)((char *)hdr + be16_to_cpu(*tagp)); /* * If it's not free then can't do this add without cleaning up: * the space before the first leaf entry needs to be free so it * can be expanded to hold the pointer to the new entry. */ if (be16_to_cpu(enddup->freetag) == XFS_DIR2_DATA_FREE_TAG) { /* * Check out the biggest freespace and see if it's the same one. */ dup = (xfs_dir2_data_unused_t *) ((char *)hdr + be16_to_cpu(bf[0].offset)); if (dup != enddup) { /* * Not the same free entry, just check its length. */ if (be16_to_cpu(dup->length) < len) dup = NULL; goto out; } /* * It is the biggest freespace, can it hold the leaf too? */ if (be16_to_cpu(dup->length) < len + (uint)sizeof(*blp)) { /* * Yes, use the second-largest entry instead if it works. */ if (be16_to_cpu(bf[1].length) >= len) dup = (xfs_dir2_data_unused_t *) ((char *)hdr + be16_to_cpu(bf[1].offset)); else dup = NULL; } } out: *tagpp = tagp; *dupp = dup; *enddupp = enddup; } /* * compact the leaf entries. * Leave the highest-numbered stale entry stale. * XXX should be the one closest to mid but mid is not yet computed. */ static void xfs_dir2_block_compact( struct xfs_da_args *args, struct xfs_buf *bp, struct xfs_dir2_data_hdr *hdr, struct xfs_dir2_block_tail *btp, struct xfs_dir2_leaf_entry *blp, int *needlog, int *lfloghigh, int *lfloglow) { int fromidx; /* source leaf index */ int toidx; /* target leaf index */ int needscan = 0; int highstale; /* high stale index */ fromidx = toidx = be32_to_cpu(btp->count) - 1; highstale = *lfloghigh = -1; for (; fromidx >= 0; fromidx--) { if (blp[fromidx].address == cpu_to_be32(XFS_DIR2_NULL_DATAPTR)) { if (highstale == -1) highstale = toidx; else { if (*lfloghigh == -1) *lfloghigh = toidx; continue; } } if (fromidx < toidx) blp[toidx] = blp[fromidx]; toidx--; } *lfloglow = toidx + 1 - (be32_to_cpu(btp->stale) - 1); *lfloghigh -= be32_to_cpu(btp->stale) - 1; be32_add_cpu(&btp->count, -(be32_to_cpu(btp->stale) - 1)); xfs_dir2_data_make_free(args, bp, (xfs_dir2_data_aoff_t)((char *)blp - (char *)hdr), (xfs_dir2_data_aoff_t)((be32_to_cpu(btp->stale) - 1) * sizeof(*blp)), needlog, &needscan); btp->stale = cpu_to_be32(1); /* * If we now need to rebuild the bestfree map, do so. * This needs to happen before the next call to use_free. */ if (needscan) xfs_dir2_data_freescan(args->dp, hdr, needlog); } /* * Add an entry to a block directory. */ int /* error */ xfs_dir2_block_addname( xfs_da_args_t *args) /* directory op arguments */ { xfs_dir2_data_hdr_t *hdr; /* block header */ xfs_dir2_leaf_entry_t *blp; /* block leaf entries */ struct xfs_buf *bp; /* buffer for block */ xfs_dir2_block_tail_t *btp; /* block tail */ int compact; /* need to compact leaf ents */ xfs_dir2_data_entry_t *dep; /* block data entry */ xfs_inode_t *dp; /* directory inode */ xfs_dir2_data_unused_t *dup; /* block unused entry */ int error; /* error return value */ xfs_dir2_data_unused_t *enddup=NULL; /* unused at end of data */ xfs_dahash_t hash; /* hash value of found entry */ int high; /* high index for binary srch */ int highstale; /* high stale index */ int lfloghigh=0; /* last final leaf to log */ int lfloglow=0; /* first final leaf to log */ int len; /* length of the new entry */ int low; /* low index for binary srch */ int lowstale; /* low stale index */ int mid=0; /* midpoint for binary srch */ int needlog; /* need to log header */ int needscan; /* need to rescan freespace */ __be16 *tagp; /* pointer to tag value */ xfs_trans_t *tp; /* transaction structure */ trace_xfs_dir2_block_addname(args); dp = args->dp; tp = args->trans; /* Read the (one and only) directory block into bp. */ error = xfs_dir3_block_read(tp, dp, &bp); if (error) return error; len = dp->d_ops->data_entsize(args->namelen); /* * Set up pointers to parts of the block. */ hdr = bp->b_addr; btp = xfs_dir2_block_tail_p(args->geo, hdr); blp = xfs_dir2_block_leaf_p(btp); /* * Find out if we can reuse stale entries or whether we need extra * space for entry and new leaf. */ xfs_dir2_block_need_space(dp, hdr, btp, blp, &tagp, &dup, &enddup, &compact, len); /* * Done everything we need for a space check now. */ if (args->op_flags & XFS_DA_OP_JUSTCHECK) { xfs_trans_brelse(tp, bp); if (!dup) return -ENOSPC; return 0; } /* * If we don't have space for the new entry & leaf ... */ if (!dup) { /* Don't have a space reservation: return no-space. */ if (args->total == 0) return -ENOSPC; /* * Convert to the next larger format. * Then add the new entry in that format. */ error = xfs_dir2_block_to_leaf(args, bp); if (error) return error; return xfs_dir2_leaf_addname(args); } needlog = needscan = 0; /* * If need to compact the leaf entries, do it now. */ if (compact) { xfs_dir2_block_compact(args, bp, hdr, btp, blp, &needlog, &lfloghigh, &lfloglow); /* recalculate blp post-compaction */ blp = xfs_dir2_block_leaf_p(btp); } else if (btp->stale) { /* * Set leaf logging boundaries to impossible state. * For the no-stale case they're set explicitly. */ lfloglow = be32_to_cpu(btp->count); lfloghigh = -1; } /* * Find the slot that's first lower than our hash value, -1 if none. */ for (low = 0, high = be32_to_cpu(btp->count) - 1; low <= high; ) { mid = (low + high) >> 1; if ((hash = be32_to_cpu(blp[mid].hashval)) == args->hashval) break; if (hash < args->hashval) low = mid + 1; else high = mid - 1; } while (mid >= 0 && be32_to_cpu(blp[mid].hashval) >= args->hashval) { mid--; } /* * No stale entries, will use enddup space to hold new leaf. */ if (!btp->stale) { /* * Mark the space needed for the new leaf entry, now in use. */ xfs_dir2_data_use_free(args, bp, enddup, (xfs_dir2_data_aoff_t) ((char *)enddup - (char *)hdr + be16_to_cpu(enddup->length) - sizeof(*blp)), (xfs_dir2_data_aoff_t)sizeof(*blp), &needlog, &needscan); /* * Update the tail (entry count). */ be32_add_cpu(&btp->count, 1); /* * If we now need to rebuild the bestfree map, do so. * This needs to happen before the next call to use_free. */ if (needscan) { xfs_dir2_data_freescan(dp, hdr, &needlog); needscan = 0; } /* * Adjust pointer to the first leaf entry, we're about to move * the table up one to open up space for the new leaf entry. * Then adjust our index to match. */ blp--; mid++; if (mid) memmove(blp, &blp[1], mid * sizeof(*blp)); lfloglow = 0; lfloghigh = mid; } /* * Use a stale leaf for our new entry. */ else { for (lowstale = mid; lowstale >= 0 && blp[lowstale].address != cpu_to_be32(XFS_DIR2_NULL_DATAPTR); lowstale--) continue; for (highstale = mid + 1; highstale < be32_to_cpu(btp->count) && blp[highstale].address != cpu_to_be32(XFS_DIR2_NULL_DATAPTR) && (lowstale < 0 || mid - lowstale > highstale - mid); highstale++) continue; /* * Move entries toward the low-numbered stale entry. */ if (lowstale >= 0 && (highstale == be32_to_cpu(btp->count) || mid - lowstale <= highstale - mid)) { if (mid - lowstale) memmove(&blp[lowstale], &blp[lowstale + 1], (mid - lowstale) * sizeof(*blp)); lfloglow = MIN(lowstale, lfloglow); lfloghigh = MAX(mid, lfloghigh); } /* * Move entries toward the high-numbered stale entry. */ else { ASSERT(highstale < be32_to_cpu(btp->count)); mid++; if (highstale - mid) memmove(&blp[mid + 1], &blp[mid], (highstale - mid) * sizeof(*blp)); lfloglow = MIN(mid, lfloglow); lfloghigh = MAX(highstale, lfloghigh); } be32_add_cpu(&btp->stale, -1); } /* * Point to the new data entry. */ dep = (xfs_dir2_data_entry_t *)dup; /* * Fill in the leaf entry. */ blp[mid].hashval = cpu_to_be32(args->hashval); blp[mid].address = cpu_to_be32(xfs_dir2_byte_to_dataptr( (char *)dep - (char *)hdr)); xfs_dir2_block_log_leaf(tp, bp, lfloglow, lfloghigh); /* * Mark space for the data entry used. */ xfs_dir2_data_use_free(args, bp, dup, (xfs_dir2_data_aoff_t)((char *)dup - (char *)hdr), (xfs_dir2_data_aoff_t)len, &needlog, &needscan); /* * Create the new data entry. */ dep->inumber = cpu_to_be64(args->inumber); dep->namelen = args->namelen; memcpy(dep->name, args->name, args->namelen); dp->d_ops->data_put_ftype(dep, args->filetype); tagp = dp->d_ops->data_entry_tag_p(dep); *tagp = cpu_to_be16((char *)dep - (char *)hdr); /* * Clean up the bestfree array and log the header, tail, and entry. */ if (needscan) xfs_dir2_data_freescan(dp, hdr, &needlog); if (needlog) xfs_dir2_data_log_header(args, bp); xfs_dir2_block_log_tail(tp, bp); xfs_dir2_data_log_entry(args, bp, dep); xfs_dir3_data_check(dp, bp); return 0; } /* * Log leaf entries from the block. */ static void xfs_dir2_block_log_leaf( xfs_trans_t *tp, /* transaction structure */ struct xfs_buf *bp, /* block buffer */ int first, /* index of first logged leaf */ int last) /* index of last logged leaf */ { xfs_dir2_data_hdr_t *hdr = bp->b_addr; xfs_dir2_leaf_entry_t *blp; xfs_dir2_block_tail_t *btp; btp = xfs_dir2_block_tail_p(tp->t_mountp->m_dir_geo, hdr); blp = xfs_dir2_block_leaf_p(btp); xfs_trans_log_buf(tp, bp, (uint)((char *)&blp[first] - (char *)hdr), (uint)((char *)&blp[last + 1] - (char *)hdr - 1)); } /* * Log the block tail. */ static void xfs_dir2_block_log_tail( xfs_trans_t *tp, /* transaction structure */ struct xfs_buf *bp) /* block buffer */ { xfs_dir2_data_hdr_t *hdr = bp->b_addr; xfs_dir2_block_tail_t *btp; btp = xfs_dir2_block_tail_p(tp->t_mountp->m_dir_geo, hdr); xfs_trans_log_buf(tp, bp, (uint)((char *)btp - (char *)hdr), (uint)((char *)(btp + 1) - (char *)hdr - 1)); } /* * Look up an entry in the block. This is the external routine, * xfs_dir2_block_lookup_int does the real work. */ int /* error */ xfs_dir2_block_lookup( xfs_da_args_t *args) /* dir lookup arguments */ { xfs_dir2_data_hdr_t *hdr; /* block header */ xfs_dir2_leaf_entry_t *blp; /* block leaf entries */ struct xfs_buf *bp; /* block buffer */ xfs_dir2_block_tail_t *btp; /* block tail */ xfs_dir2_data_entry_t *dep; /* block data entry */ xfs_inode_t *dp; /* incore inode */ int ent; /* entry index */ int error; /* error return value */ trace_xfs_dir2_block_lookup(args); /* * Get the buffer, look up the entry. * If not found (ENOENT) then return, have no buffer. */ if ((error = xfs_dir2_block_lookup_int(args, &bp, &ent))) return error; dp = args->dp; hdr = bp->b_addr; xfs_dir3_data_check(dp, bp); btp = xfs_dir2_block_tail_p(args->geo, hdr); blp = xfs_dir2_block_leaf_p(btp); /* * Get the offset from the leaf entry, to point to the data. */ dep = (xfs_dir2_data_entry_t *)((char *)hdr + xfs_dir2_dataptr_to_off(args->geo, be32_to_cpu(blp[ent].address))); /* * Fill in inode number, CI name if appropriate, release the block. */ args->inumber = be64_to_cpu(dep->inumber); args->filetype = dp->d_ops->data_get_ftype(dep); error = xfs_dir_cilookup_result(args, dep->name, dep->namelen); xfs_trans_brelse(args->trans, bp); return error; } /* * Internal block lookup routine. */ static int /* error */ xfs_dir2_block_lookup_int( xfs_da_args_t *args, /* dir lookup arguments */ struct xfs_buf **bpp, /* returned block buffer */ int *entno) /* returned entry number */ { xfs_dir2_dataptr_t addr; /* data entry address */ xfs_dir2_data_hdr_t *hdr; /* block header */ xfs_dir2_leaf_entry_t *blp; /* block leaf entries */ struct xfs_buf *bp; /* block buffer */ xfs_dir2_block_tail_t *btp; /* block tail */ xfs_dir2_data_entry_t *dep; /* block data entry */ xfs_inode_t *dp; /* incore inode */ int error; /* error return value */ xfs_dahash_t hash; /* found hash value */ int high; /* binary search high index */ int low; /* binary search low index */ int mid; /* binary search current idx */ xfs_mount_t *mp; /* filesystem mount point */ xfs_trans_t *tp; /* transaction pointer */ enum xfs_dacmp cmp; /* comparison result */ dp = args->dp; tp = args->trans; mp = dp->i_mount; error = xfs_dir3_block_read(tp, dp, &bp); if (error) return error; hdr = bp->b_addr; xfs_dir3_data_check(dp, bp); btp = xfs_dir2_block_tail_p(args->geo, hdr); blp = xfs_dir2_block_leaf_p(btp); /* * Loop doing a binary search for our hash value. * Find our entry, ENOENT if it's not there. */ for (low = 0, high = be32_to_cpu(btp->count) - 1; ; ) { ASSERT(low <= high); mid = (low + high) >> 1; if ((hash = be32_to_cpu(blp[mid].hashval)) == args->hashval) break; if (hash < args->hashval) low = mid + 1; else high = mid - 1; if (low > high) { ASSERT(args->op_flags & XFS_DA_OP_OKNOENT); xfs_trans_brelse(tp, bp); return -ENOENT; } } /* * Back up to the first one with the right hash value. */ while (mid > 0 && be32_to_cpu(blp[mid - 1].hashval) == args->hashval) { mid--; } /* * Now loop forward through all the entries with the * right hash value looking for our name. */ do { if ((addr = be32_to_cpu(blp[mid].address)) == XFS_DIR2_NULL_DATAPTR) continue; /* * Get pointer to the entry from the leaf. */ dep = (xfs_dir2_data_entry_t *) ((char *)hdr + xfs_dir2_dataptr_to_off(args->geo, addr)); /* * Compare name and if it's an exact match, return the index * and buffer. If it's the first case-insensitive match, store * the index and buffer and continue looking for an exact match. */ cmp = mp->m_dirnameops->compname(args, dep->name, dep->namelen); if (cmp != XFS_CMP_DIFFERENT && cmp != args->cmpresult) { args->cmpresult = cmp; *bpp = bp; *entno = mid; if (cmp == XFS_CMP_EXACT) return 0; } } while (++mid < be32_to_cpu(btp->count) && be32_to_cpu(blp[mid].hashval) == hash); ASSERT(args->op_flags & XFS_DA_OP_OKNOENT); /* * Here, we can only be doing a lookup (not a rename or replace). * If a case-insensitive match was found earlier, return success. */ if (args->cmpresult == XFS_CMP_CASE) return 0; /* * No match, release the buffer and return ENOENT. */ xfs_trans_brelse(tp, bp); return -ENOENT; } /* * Remove an entry from a block format directory. * If that makes the block small enough to fit in shortform, transform it. */ int /* error */ xfs_dir2_block_removename( xfs_da_args_t *args) /* directory operation args */ { xfs_dir2_data_hdr_t *hdr; /* block header */ xfs_dir2_leaf_entry_t *blp; /* block leaf pointer */ struct xfs_buf *bp; /* block buffer */ xfs_dir2_block_tail_t *btp; /* block tail */ xfs_dir2_data_entry_t *dep; /* block data entry */ xfs_inode_t *dp; /* incore inode */ int ent; /* block leaf entry index */ int error; /* error return value */ int needlog; /* need to log block header */ int needscan; /* need to fixup bestfree */ xfs_dir2_sf_hdr_t sfh; /* shortform header */ int size; /* shortform size */ xfs_trans_t *tp; /* transaction pointer */ trace_xfs_dir2_block_removename(args); /* * Look up the entry in the block. Gets the buffer and entry index. * It will always be there, the vnodeops level does a lookup first. */ if ((error = xfs_dir2_block_lookup_int(args, &bp, &ent))) { return error; } dp = args->dp; tp = args->trans; hdr = bp->b_addr; btp = xfs_dir2_block_tail_p(args->geo, hdr); blp = xfs_dir2_block_leaf_p(btp); /* * Point to the data entry using the leaf entry. */ dep = (xfs_dir2_data_entry_t *)((char *)hdr + xfs_dir2_dataptr_to_off(args->geo, be32_to_cpu(blp[ent].address))); /* * Mark the data entry's space free. */ needlog = needscan = 0; xfs_dir2_data_make_free(args, bp, (xfs_dir2_data_aoff_t)((char *)dep - (char *)hdr), dp->d_ops->data_entsize(dep->namelen), &needlog, &needscan); /* * Fix up the block tail. */ be32_add_cpu(&btp->stale, 1); xfs_dir2_block_log_tail(tp, bp); /* * Remove the leaf entry by marking it stale. */ blp[ent].address = cpu_to_be32(XFS_DIR2_NULL_DATAPTR); xfs_dir2_block_log_leaf(tp, bp, ent, ent); /* * Fix up bestfree, log the header if necessary. */ if (needscan) xfs_dir2_data_freescan(dp, hdr, &needlog); if (needlog) xfs_dir2_data_log_header(args, bp); xfs_dir3_data_check(dp, bp); /* * See if the size as a shortform is good enough. */ size = xfs_dir2_block_sfsize(dp, hdr, &sfh); if (size > XFS_IFORK_DSIZE(dp)) return 0; /* * If it works, do the conversion. */ return xfs_dir2_block_to_sf(args, bp, size, &sfh); } /* * Replace an entry in a V2 block directory. * Change the inode number to the new value. */ int /* error */ xfs_dir2_block_replace( xfs_da_args_t *args) /* directory operation args */ { xfs_dir2_data_hdr_t *hdr; /* block header */ xfs_dir2_leaf_entry_t *blp; /* block leaf entries */ struct xfs_buf *bp; /* block buffer */ xfs_dir2_block_tail_t *btp; /* block tail */ xfs_dir2_data_entry_t *dep; /* block data entry */ xfs_inode_t *dp; /* incore inode */ int ent; /* leaf entry index */ int error; /* error return value */ trace_xfs_dir2_block_replace(args); /* * Lookup the entry in the directory. Get buffer and entry index. * This will always succeed since the caller has already done a lookup. */ if ((error = xfs_dir2_block_lookup_int(args, &bp, &ent))) { return error; } dp = args->dp; hdr = bp->b_addr; btp = xfs_dir2_block_tail_p(args->geo, hdr); blp = xfs_dir2_block_leaf_p(btp); /* * Point to the data entry we need to change. */ dep = (xfs_dir2_data_entry_t *)((char *)hdr + xfs_dir2_dataptr_to_off(args->geo, be32_to_cpu(blp[ent].address))); ASSERT(be64_to_cpu(dep->inumber) != args->inumber); /* * Change the inode number to the new value. */ dep->inumber = cpu_to_be64(args->inumber); dp->d_ops->data_put_ftype(dep, args->filetype); xfs_dir2_data_log_entry(args, bp, dep); xfs_dir3_data_check(dp, bp); return 0; } /* * Qsort comparison routine for the block leaf entries. */ static int /* sort order */ xfs_dir2_block_sort( const void *a, /* first leaf entry */ const void *b) /* second leaf entry */ { const xfs_dir2_leaf_entry_t *la; /* first leaf entry */ const xfs_dir2_leaf_entry_t *lb; /* second leaf entry */ la = a; lb = b; return be32_to_cpu(la->hashval) < be32_to_cpu(lb->hashval) ? -1 : (be32_to_cpu(la->hashval) > be32_to_cpu(lb->hashval) ? 1 : 0); } /* * Convert a V2 leaf directory to a V2 block directory if possible. */ int /* error */ xfs_dir2_leaf_to_block( xfs_da_args_t *args, /* operation arguments */ struct xfs_buf *lbp, /* leaf buffer */ struct xfs_buf *dbp) /* data buffer */ { __be16 *bestsp; /* leaf bests table */ xfs_dir2_data_hdr_t *hdr; /* block header */ xfs_dir2_block_tail_t *btp; /* block tail */ xfs_inode_t *dp; /* incore directory inode */ xfs_dir2_data_unused_t *dup; /* unused data entry */ int error; /* error return value */ int from; /* leaf from index */ xfs_dir2_leaf_t *leaf; /* leaf structure */ xfs_dir2_leaf_entry_t *lep; /* leaf entry */ xfs_dir2_leaf_tail_t *ltp; /* leaf tail structure */ xfs_mount_t *mp; /* file system mount point */ int needlog; /* need to log data header */ int needscan; /* need to scan for bestfree */ xfs_dir2_sf_hdr_t sfh; /* shortform header */ int size; /* bytes used */ __be16 *tagp; /* end of entry (tag) */ int to; /* block/leaf to index */ xfs_trans_t *tp; /* transaction pointer */ struct xfs_dir2_leaf_entry *ents; struct xfs_dir3_icleaf_hdr leafhdr; trace_xfs_dir2_leaf_to_block(args); dp = args->dp; tp = args->trans; mp = dp->i_mount; leaf = lbp->b_addr; dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf); ents = dp->d_ops->leaf_ents_p(leaf); ltp = xfs_dir2_leaf_tail_p(args->geo, leaf); ASSERT(leafhdr.magic == XFS_DIR2_LEAF1_MAGIC || leafhdr.magic == XFS_DIR3_LEAF1_MAGIC); /* * If there are data blocks other than the first one, take this * opportunity to remove trailing empty data blocks that may have * been left behind during no-space-reservation operations. * These will show up in the leaf bests table. */ while (dp->i_d.di_size > args->geo->blksize) { int hdrsz; hdrsz = dp->d_ops->data_entry_offset; bestsp = xfs_dir2_leaf_bests_p(ltp); if (be16_to_cpu(bestsp[be32_to_cpu(ltp->bestcount) - 1]) == args->geo->blksize - hdrsz) { if ((error = xfs_dir2_leaf_trim_data(args, lbp, (xfs_dir2_db_t)(be32_to_cpu(ltp->bestcount) - 1)))) return error; } else return 0; } /* * Read the data block if we don't already have it, give up if it fails. */ if (!dbp) { error = xfs_dir3_data_read(tp, dp, args->geo->datablk, -1, &dbp); if (error) return error; } hdr = dbp->b_addr; ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC)); /* * Size of the "leaf" area in the block. */ size = (uint)sizeof(xfs_dir2_block_tail_t) + (uint)sizeof(*lep) * (leafhdr.count - leafhdr.stale); /* * Look at the last data entry. */ tagp = (__be16 *)((char *)hdr + args->geo->blksize) - 1; dup = (xfs_dir2_data_unused_t *)((char *)hdr + be16_to_cpu(*tagp)); /* * If it's not free or is too short we can't do it. */ if (be16_to_cpu(dup->freetag) != XFS_DIR2_DATA_FREE_TAG || be16_to_cpu(dup->length) < size) return 0; /* * Start converting it to block form. */ xfs_dir3_block_init(mp, tp, dbp, dp); needlog = 1; needscan = 0; /* * Use up the space at the end of the block (blp/btp). */ xfs_dir2_data_use_free(args, dbp, dup, args->geo->blksize - size, size, &needlog, &needscan); /* * Initialize the block tail. */ btp = xfs_dir2_block_tail_p(args->geo, hdr); btp->count = cpu_to_be32(leafhdr.count - leafhdr.stale); btp->stale = 0; xfs_dir2_block_log_tail(tp, dbp); /* * Initialize the block leaf area. We compact out stale entries. */ lep = xfs_dir2_block_leaf_p(btp); for (from = to = 0; from < leafhdr.count; from++) { if (ents[from].address == cpu_to_be32(XFS_DIR2_NULL_DATAPTR)) continue; lep[to++] = ents[from]; } ASSERT(to == be32_to_cpu(btp->count)); xfs_dir2_block_log_leaf(tp, dbp, 0, be32_to_cpu(btp->count) - 1); /* * Scan the bestfree if we need it and log the data block header. */ if (needscan) xfs_dir2_data_freescan(dp, hdr, &needlog); if (needlog) xfs_dir2_data_log_header(args, dbp); /* * Pitch the old leaf block. */ error = xfs_da_shrink_inode(args, args->geo->leafblk, lbp); if (error) return error; /* * Now see if the resulting block can be shrunken to shortform. */ size = xfs_dir2_block_sfsize(dp, hdr, &sfh); if (size > XFS_IFORK_DSIZE(dp)) return 0; return xfs_dir2_block_to_sf(args, dbp, size, &sfh); } /* * Convert the shortform directory to block form. */ int /* error */ xfs_dir2_sf_to_block( xfs_da_args_t *args) /* operation arguments */ { xfs_dir2_db_t blkno; /* dir-relative block # (0) */ xfs_dir2_data_hdr_t *hdr; /* block header */ xfs_dir2_leaf_entry_t *blp; /* block leaf entries */ struct xfs_buf *bp; /* block buffer */ xfs_dir2_block_tail_t *btp; /* block tail pointer */ xfs_dir2_data_entry_t *dep; /* data entry pointer */ xfs_inode_t *dp; /* incore directory inode */ int dummy; /* trash */ xfs_dir2_data_unused_t *dup; /* unused entry pointer */ int endoffset; /* end of data objects */ int error; /* error return value */ int i; /* index */ xfs_mount_t *mp; /* filesystem mount point */ int needlog; /* need to log block header */ int needscan; /* need to scan block freespc */ int newoffset; /* offset from current entry */ int offset; /* target block offset */ xfs_dir2_sf_entry_t *sfep; /* sf entry pointer */ xfs_dir2_sf_hdr_t *oldsfp; /* old shortform header */ xfs_dir2_sf_hdr_t *sfp; /* shortform header */ __be16 *tagp; /* end of data entry */ xfs_trans_t *tp; /* transaction pointer */ struct xfs_name name; struct xfs_ifork *ifp; trace_xfs_dir2_sf_to_block(args); dp = args->dp; tp = args->trans; mp = dp->i_mount; ifp = XFS_IFORK_PTR(dp, XFS_DATA_FORK); ASSERT(ifp->if_flags & XFS_IFINLINE); /* * Bomb out if the shortform directory is way too short. */ if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) { ASSERT(XFS_FORCED_SHUTDOWN(mp)); return -EIO; } oldsfp = (xfs_dir2_sf_hdr_t *)ifp->if_u1.if_data; ASSERT(ifp->if_bytes == dp->i_d.di_size); ASSERT(ifp->if_u1.if_data != NULL); ASSERT(dp->i_d.di_size >= xfs_dir2_sf_hdr_size(oldsfp->i8count)); ASSERT(dp->i_d.di_nextents == 0); /* * Copy the directory into a temporary buffer. * Then pitch the incore inode data so we can make extents. */ sfp = kmem_alloc(ifp->if_bytes, KM_SLEEP); memcpy(sfp, oldsfp, ifp->if_bytes); xfs_idata_realloc(dp, -ifp->if_bytes, XFS_DATA_FORK); xfs_bmap_local_to_extents_empty(dp, XFS_DATA_FORK); dp->i_d.di_size = 0; /* * Add block 0 to the inode. */ error = xfs_dir2_grow_inode(args, XFS_DIR2_DATA_SPACE, &blkno); if (error) { kmem_free(sfp); return error; } /* * Initialize the data block, then convert it to block format. */ error = xfs_dir3_data_init(args, blkno, &bp); if (error) { kmem_free(sfp); return error; } xfs_dir3_block_init(mp, tp, bp, dp); hdr = bp->b_addr; /* * Compute size of block "tail" area. */ i = (uint)sizeof(*btp) + (sfp->count + 2) * (uint)sizeof(xfs_dir2_leaf_entry_t); /* * The whole thing is initialized to free by the init routine. * Say we're using the leaf and tail area. */ dup = dp->d_ops->data_unused_p(hdr); needlog = needscan = 0; xfs_dir2_data_use_free(args, bp, dup, args->geo->blksize - i, i, &needlog, &needscan); ASSERT(needscan == 0); /* * Fill in the tail. */ btp = xfs_dir2_block_tail_p(args->geo, hdr); btp->count = cpu_to_be32(sfp->count + 2); /* ., .. */ btp->stale = 0; blp = xfs_dir2_block_leaf_p(btp); endoffset = (uint)((char *)blp - (char *)hdr); /* * Remove the freespace, we'll manage it. */ xfs_dir2_data_use_free(args, bp, dup, (xfs_dir2_data_aoff_t)((char *)dup - (char *)hdr), be16_to_cpu(dup->length), &needlog, &needscan); /* * Create entry for . */ dep = dp->d_ops->data_dot_entry_p(hdr); dep->inumber = cpu_to_be64(dp->i_ino); dep->namelen = 1; dep->name[0] = '.'; dp->d_ops->data_put_ftype(dep, XFS_DIR3_FT_DIR); tagp = dp->d_ops->data_entry_tag_p(dep); *tagp = cpu_to_be16((char *)dep - (char *)hdr); xfs_dir2_data_log_entry(args, bp, dep); blp[0].hashval = cpu_to_be32(xfs_dir_hash_dot); blp[0].address = cpu_to_be32(xfs_dir2_byte_to_dataptr( (char *)dep - (char *)hdr)); /* * Create entry for .. */ dep = dp->d_ops->data_dotdot_entry_p(hdr); dep->inumber = cpu_to_be64(dp->d_ops->sf_get_parent_ino(sfp)); dep->namelen = 2; dep->name[0] = dep->name[1] = '.'; dp->d_ops->data_put_ftype(dep, XFS_DIR3_FT_DIR); tagp = dp->d_ops->data_entry_tag_p(dep); *tagp = cpu_to_be16((char *)dep - (char *)hdr); xfs_dir2_data_log_entry(args, bp, dep); blp[1].hashval = cpu_to_be32(xfs_dir_hash_dotdot); blp[1].address = cpu_to_be32(xfs_dir2_byte_to_dataptr( (char *)dep - (char *)hdr)); offset = dp->d_ops->data_first_offset; /* * Loop over existing entries, stuff them in. */ i = 0; if (!sfp->count) sfep = NULL; else sfep = xfs_dir2_sf_firstentry(sfp); /* * Need to preserve the existing offset values in the sf directory. * Insert holes (unused entries) where necessary. */ while (offset < endoffset) { /* * sfep is null when we reach the end of the list. */ if (sfep == NULL) newoffset = endoffset; else newoffset = xfs_dir2_sf_get_offset(sfep); /* * There should be a hole here, make one. */ if (offset < newoffset) { dup = (xfs_dir2_data_unused_t *)((char *)hdr + offset); dup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG); dup->length = cpu_to_be16(newoffset - offset); *xfs_dir2_data_unused_tag_p(dup) = cpu_to_be16( ((char *)dup - (char *)hdr)); xfs_dir2_data_log_unused(args, bp, dup); xfs_dir2_data_freeinsert(hdr, dp->d_ops->data_bestfree_p(hdr), dup, &dummy); offset += be16_to_cpu(dup->length); continue; } /* * Copy a real entry. */ dep = (xfs_dir2_data_entry_t *)((char *)hdr + newoffset); dep->inumber = cpu_to_be64(dp->d_ops->sf_get_ino(sfp, sfep)); dep->namelen = sfep->namelen; dp->d_ops->data_put_ftype(dep, dp->d_ops->sf_get_ftype(sfep)); memcpy(dep->name, sfep->name, dep->namelen); tagp = dp->d_ops->data_entry_tag_p(dep); *tagp = cpu_to_be16((char *)dep - (char *)hdr); xfs_dir2_data_log_entry(args, bp, dep); name.name = sfep->name; name.len = sfep->namelen; blp[2 + i].hashval = cpu_to_be32(mp->m_dirnameops-> hashname(&name)); blp[2 + i].address = cpu_to_be32(xfs_dir2_byte_to_dataptr( (char *)dep - (char *)hdr)); offset = (int)((char *)(tagp + 1) - (char *)hdr); if (++i == sfp->count) sfep = NULL; else sfep = dp->d_ops->sf_nextentry(sfp, sfep); } /* Done with the temporary buffer */ kmem_free(sfp); /* * Sort the leaf entries by hash value. */ xfs_sort(blp, be32_to_cpu(btp->count), sizeof(*blp), xfs_dir2_block_sort); /* * Log the leaf entry area and tail. * Already logged the header in data_init, ignore needlog. */ ASSERT(needscan == 0); xfs_dir2_block_log_leaf(tp, bp, 0, be32_to_cpu(btp->count) - 1); xfs_dir2_block_log_tail(tp, bp); xfs_dir3_data_check(dp, bp); return 0; } partclone-0.2.86/src/xfs/xfs_dir2_data.c000066400000000000000000000746321262102574200200570ustar00rootroot00000000000000/* * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. * Copyright (c) 2013 Red Hat, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_mount.h" #include "xfs_da_format.h" #include "xfs_da_btree.h" #include "xfs_inode.h" #include "xfs_dir2.h" #include "xfs_dir2_priv.h" #include "xfs_trans.h" #include "xfs_cksum.h" /* * Check the consistency of the data block. * The input can also be a block-format directory. * Return 0 is the buffer is good, otherwise an error. */ int __xfs_dir3_data_check( struct xfs_inode *dp, /* incore inode pointer */ struct xfs_buf *bp) /* data block's buffer */ { xfs_dir2_dataptr_t addr; /* addr for leaf lookup */ xfs_dir2_data_free_t *bf; /* bestfree table */ xfs_dir2_block_tail_t *btp=NULL; /* block tail */ int count; /* count of entries found */ xfs_dir2_data_hdr_t *hdr; /* data block header */ xfs_dir2_data_entry_t *dep; /* data entry */ xfs_dir2_data_free_t *dfp; /* bestfree entry */ xfs_dir2_data_unused_t *dup; /* unused entry */ char *endp; /* end of useful data */ int freeseen; /* mask of bestfrees seen */ xfs_dahash_t hash; /* hash of current name */ int i; /* leaf index */ int lastfree; /* last entry was unused */ xfs_dir2_leaf_entry_t *lep=NULL; /* block leaf entries */ xfs_mount_t *mp; /* filesystem mount point */ char *p; /* current data position */ int stale; /* count of stale leaves */ struct xfs_name name; const struct xfs_dir_ops *ops; struct xfs_da_geometry *geo; mp = bp->b_target->bt_mount; geo = mp->m_dir_geo; /* * We can be passed a null dp here from a verifier, so we need to go the * hard way to get them. */ ops = xfs_dir_get_ops(mp, dp); hdr = bp->b_addr; p = (char *)ops->data_entry_p(hdr); switch (hdr->magic) { case cpu_to_be32(XFS_DIR3_BLOCK_MAGIC): case cpu_to_be32(XFS_DIR2_BLOCK_MAGIC): btp = xfs_dir2_block_tail_p(geo, hdr); lep = xfs_dir2_block_leaf_p(btp); endp = (char *)lep; /* * The number of leaf entries is limited by the size of the * block and the amount of space used by the data entries. * We don't know how much space is used by the data entries yet, * so just ensure that the count falls somewhere inside the * block right now. */ XFS_WANT_CORRUPTED_RETURN(mp, be32_to_cpu(btp->count) < ((char *)btp - p) / sizeof(struct xfs_dir2_leaf_entry)); break; case cpu_to_be32(XFS_DIR3_DATA_MAGIC): case cpu_to_be32(XFS_DIR2_DATA_MAGIC): endp = (char *)hdr + geo->blksize; break; default: XFS_ERROR_REPORT("Bad Magic", XFS_ERRLEVEL_LOW, mp); return -EFSCORRUPTED; } /* * Account for zero bestfree entries. */ bf = ops->data_bestfree_p(hdr); count = lastfree = freeseen = 0; if (!bf[0].length) { XFS_WANT_CORRUPTED_RETURN(mp, !bf[0].offset); freeseen |= 1 << 0; } if (!bf[1].length) { XFS_WANT_CORRUPTED_RETURN(mp, !bf[1].offset); freeseen |= 1 << 1; } if (!bf[2].length) { XFS_WANT_CORRUPTED_RETURN(mp, !bf[2].offset); freeseen |= 1 << 2; } XFS_WANT_CORRUPTED_RETURN(mp, be16_to_cpu(bf[0].length) >= be16_to_cpu(bf[1].length)); XFS_WANT_CORRUPTED_RETURN(mp, be16_to_cpu(bf[1].length) >= be16_to_cpu(bf[2].length)); /* * Loop over the data/unused entries. */ while (p < endp) { dup = (xfs_dir2_data_unused_t *)p; /* * If it's unused, look for the space in the bestfree table. * If we find it, account for that, else make sure it * doesn't need to be there. */ if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) { XFS_WANT_CORRUPTED_RETURN(mp, lastfree == 0); XFS_WANT_CORRUPTED_RETURN(mp, be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup)) == (char *)dup - (char *)hdr); dfp = xfs_dir2_data_freefind(hdr, bf, dup); if (dfp) { i = (int)(dfp - bf); XFS_WANT_CORRUPTED_RETURN(mp, (freeseen & (1 << i)) == 0); freeseen |= 1 << i; } else { XFS_WANT_CORRUPTED_RETURN(mp, be16_to_cpu(dup->length) <= be16_to_cpu(bf[2].length)); } p += be16_to_cpu(dup->length); lastfree = 1; continue; } /* * It's a real entry. Validate the fields. * If this is a block directory then make sure it's * in the leaf section of the block. * The linear search is crude but this is DEBUG code. */ dep = (xfs_dir2_data_entry_t *)p; XFS_WANT_CORRUPTED_RETURN(mp, dep->namelen != 0); XFS_WANT_CORRUPTED_RETURN(mp, !xfs_dir_ino_validate(mp, be64_to_cpu(dep->inumber))); XFS_WANT_CORRUPTED_RETURN(mp, be16_to_cpu(*ops->data_entry_tag_p(dep)) == (char *)dep - (char *)hdr); XFS_WANT_CORRUPTED_RETURN(mp, ops->data_get_ftype(dep) < XFS_DIR3_FT_MAX); count++; lastfree = 0; if (hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) || hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)) { addr = xfs_dir2_db_off_to_dataptr(geo, geo->datablk, (xfs_dir2_data_aoff_t) ((char *)dep - (char *)hdr)); name.name = dep->name; name.len = dep->namelen; hash = mp->m_dirnameops->hashname(&name); for (i = 0; i < be32_to_cpu(btp->count); i++) { if (be32_to_cpu(lep[i].address) == addr && be32_to_cpu(lep[i].hashval) == hash) break; } XFS_WANT_CORRUPTED_RETURN(mp, i < be32_to_cpu(btp->count)); } p += ops->data_entsize(dep->namelen); } /* * Need to have seen all the entries and all the bestfree slots. */ XFS_WANT_CORRUPTED_RETURN(mp, freeseen == 7); if (hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) || hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)) { for (i = stale = 0; i < be32_to_cpu(btp->count); i++) { if (lep[i].address == cpu_to_be32(XFS_DIR2_NULL_DATAPTR)) stale++; if (i > 0) XFS_WANT_CORRUPTED_RETURN(mp, be32_to_cpu(lep[i].hashval) >= be32_to_cpu(lep[i - 1].hashval)); } XFS_WANT_CORRUPTED_RETURN(mp, count == be32_to_cpu(btp->count) - be32_to_cpu(btp->stale)); XFS_WANT_CORRUPTED_RETURN(mp, stale == be32_to_cpu(btp->stale)); } return 0; } static bool xfs_dir3_data_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_target->bt_mount; struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr; if (xfs_sb_version_hascrc(&mp->m_sb)) { if (hdr3->magic != cpu_to_be32(XFS_DIR3_DATA_MAGIC)) return false; if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_meta_uuid)) return false; if (be64_to_cpu(hdr3->blkno) != bp->b_bn) return false; } else { if (hdr3->magic != cpu_to_be32(XFS_DIR2_DATA_MAGIC)) return false; } if (__xfs_dir3_data_check(NULL, bp)) return false; return true; } /* * Readahead of the first block of the directory when it is opened is completely * oblivious to the format of the directory. Hence we can either get a block * format buffer or a data format buffer on readahead. */ static void xfs_dir3_data_reada_verify( struct xfs_buf *bp) { struct xfs_dir2_data_hdr *hdr = bp->b_addr; switch (hdr->magic) { case cpu_to_be32(XFS_DIR2_BLOCK_MAGIC): case cpu_to_be32(XFS_DIR3_BLOCK_MAGIC): bp->b_ops = &xfs_dir3_block_buf_ops; bp->b_ops->verify_read(bp); return; case cpu_to_be32(XFS_DIR2_DATA_MAGIC): case cpu_to_be32(XFS_DIR3_DATA_MAGIC): bp->b_ops = &xfs_dir3_data_buf_ops; bp->b_ops->verify_read(bp); return; default: xfs_buf_ioerror(bp, -EFSCORRUPTED); xfs_verifier_error(bp); break; } } static void xfs_dir3_data_read_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_target->bt_mount; if (xfs_sb_version_hascrc(&mp->m_sb) && !xfs_buf_verify_cksum(bp, XFS_DIR3_DATA_CRC_OFF)) xfs_buf_ioerror(bp, -EFSBADCRC); else if (!xfs_dir3_data_verify(bp)) xfs_buf_ioerror(bp, -EFSCORRUPTED); if (bp->b_error) xfs_verifier_error(bp); } static void xfs_dir3_data_write_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_target->bt_mount; struct xfs_buf_log_item *bip = bp->b_fspriv; struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr; if (!xfs_dir3_data_verify(bp)) { xfs_buf_ioerror(bp, -EFSCORRUPTED); xfs_verifier_error(bp); return; } if (!xfs_sb_version_hascrc(&mp->m_sb)) return; if (bip) hdr3->lsn = cpu_to_be64(bip->bli_item.li_lsn); xfs_buf_update_cksum(bp, XFS_DIR3_DATA_CRC_OFF); } const struct xfs_buf_ops xfs_dir3_data_buf_ops = { .verify_read = xfs_dir3_data_read_verify, .verify_write = xfs_dir3_data_write_verify, }; static const struct xfs_buf_ops xfs_dir3_data_reada_buf_ops = { .verify_read = xfs_dir3_data_reada_verify, .verify_write = xfs_dir3_data_write_verify, }; int xfs_dir3_data_read( struct xfs_trans *tp, struct xfs_inode *dp, xfs_dablk_t bno, xfs_daddr_t mapped_bno, struct xfs_buf **bpp) { int err; err = xfs_da_read_buf(tp, dp, bno, mapped_bno, bpp, XFS_DATA_FORK, &xfs_dir3_data_buf_ops); if (!err && tp) xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_DIR_DATA_BUF); return err; } int xfs_dir3_data_readahead( struct xfs_inode *dp, xfs_dablk_t bno, xfs_daddr_t mapped_bno) { return xfs_da_reada_buf(dp, bno, mapped_bno, XFS_DATA_FORK, &xfs_dir3_data_reada_buf_ops); } /* * Given a data block and an unused entry from that block, * return the bestfree entry if any that corresponds to it. */ xfs_dir2_data_free_t * xfs_dir2_data_freefind( struct xfs_dir2_data_hdr *hdr, /* data block header */ struct xfs_dir2_data_free *bf, /* bestfree table pointer */ struct xfs_dir2_data_unused *dup) /* unused space */ { xfs_dir2_data_free_t *dfp; /* bestfree entry */ xfs_dir2_data_aoff_t off; /* offset value needed */ #ifdef DEBUG int matched; /* matched the value */ int seenzero; /* saw a 0 bestfree entry */ #endif off = (xfs_dir2_data_aoff_t)((char *)dup - (char *)hdr); #ifdef DEBUG /* * Validate some consistency in the bestfree table. * Check order, non-overlapping entries, and if we find the * one we're looking for it has to be exact. */ ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) || hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) || hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)); for (dfp = &bf[0], seenzero = matched = 0; dfp < &bf[XFS_DIR2_DATA_FD_COUNT]; dfp++) { if (!dfp->offset) { ASSERT(!dfp->length); seenzero = 1; continue; } ASSERT(seenzero == 0); if (be16_to_cpu(dfp->offset) == off) { matched = 1; ASSERT(dfp->length == dup->length); } else if (off < be16_to_cpu(dfp->offset)) ASSERT(off + be16_to_cpu(dup->length) <= be16_to_cpu(dfp->offset)); else ASSERT(be16_to_cpu(dfp->offset) + be16_to_cpu(dfp->length) <= off); ASSERT(matched || be16_to_cpu(dfp->length) >= be16_to_cpu(dup->length)); if (dfp > &bf[0]) ASSERT(be16_to_cpu(dfp[-1].length) >= be16_to_cpu(dfp[0].length)); } #endif /* * If this is smaller than the smallest bestfree entry, * it can't be there since they're sorted. */ if (be16_to_cpu(dup->length) < be16_to_cpu(bf[XFS_DIR2_DATA_FD_COUNT - 1].length)) return NULL; /* * Look at the three bestfree entries for our guy. */ for (dfp = &bf[0]; dfp < &bf[XFS_DIR2_DATA_FD_COUNT]; dfp++) { if (!dfp->offset) return NULL; if (be16_to_cpu(dfp->offset) == off) return dfp; } /* * Didn't find it. This only happens if there are duplicate lengths. */ return NULL; } /* * Insert an unused-space entry into the bestfree table. */ xfs_dir2_data_free_t * /* entry inserted */ xfs_dir2_data_freeinsert( struct xfs_dir2_data_hdr *hdr, /* data block pointer */ struct xfs_dir2_data_free *dfp, /* bestfree table pointer */ struct xfs_dir2_data_unused *dup, /* unused space */ int *loghead) /* log the data header (out) */ { xfs_dir2_data_free_t new; /* new bestfree entry */ ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) || hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) || hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)); new.length = dup->length; new.offset = cpu_to_be16((char *)dup - (char *)hdr); /* * Insert at position 0, 1, or 2; or not at all. */ if (be16_to_cpu(new.length) > be16_to_cpu(dfp[0].length)) { dfp[2] = dfp[1]; dfp[1] = dfp[0]; dfp[0] = new; *loghead = 1; return &dfp[0]; } if (be16_to_cpu(new.length) > be16_to_cpu(dfp[1].length)) { dfp[2] = dfp[1]; dfp[1] = new; *loghead = 1; return &dfp[1]; } if (be16_to_cpu(new.length) > be16_to_cpu(dfp[2].length)) { dfp[2] = new; *loghead = 1; return &dfp[2]; } return NULL; } /* * Remove a bestfree entry from the table. */ STATIC void xfs_dir2_data_freeremove( struct xfs_dir2_data_hdr *hdr, /* data block header */ struct xfs_dir2_data_free *bf, /* bestfree table pointer */ struct xfs_dir2_data_free *dfp, /* bestfree entry pointer */ int *loghead) /* out: log data header */ { ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) || hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) || hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)); /* * It's the first entry, slide the next 2 up. */ if (dfp == &bf[0]) { bf[0] = bf[1]; bf[1] = bf[2]; } /* * It's the second entry, slide the 3rd entry up. */ else if (dfp == &bf[1]) bf[1] = bf[2]; /* * Must be the last entry. */ else ASSERT(dfp == &bf[2]); /* * Clear the 3rd entry, must be zero now. */ bf[2].length = 0; bf[2].offset = 0; *loghead = 1; } /* * Given a data block, reconstruct its bestfree map. */ void __xfs_dir2_data_freescan( struct xfs_da_geometry *geo, const struct xfs_dir_ops *ops, struct xfs_dir2_data_hdr *hdr, int *loghead) { xfs_dir2_block_tail_t *btp; /* block tail */ xfs_dir2_data_entry_t *dep; /* active data entry */ xfs_dir2_data_unused_t *dup; /* unused data entry */ struct xfs_dir2_data_free *bf; char *endp; /* end of block's data */ char *p; /* current entry pointer */ ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) || hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) || hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)); /* * Start by clearing the table. */ bf = ops->data_bestfree_p(hdr); memset(bf, 0, sizeof(*bf) * XFS_DIR2_DATA_FD_COUNT); *loghead = 1; /* * Set up pointers. */ p = (char *)ops->data_entry_p(hdr); if (hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) || hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)) { btp = xfs_dir2_block_tail_p(geo, hdr); endp = (char *)xfs_dir2_block_leaf_p(btp); } else endp = (char *)hdr + geo->blksize; /* * Loop over the block's entries. */ while (p < endp) { dup = (xfs_dir2_data_unused_t *)p; /* * If it's a free entry, insert it. */ if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) { ASSERT((char *)dup - (char *)hdr == be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup))); xfs_dir2_data_freeinsert(hdr, bf, dup, loghead); p += be16_to_cpu(dup->length); } /* * For active entries, check their tags and skip them. */ else { dep = (xfs_dir2_data_entry_t *)p; ASSERT((char *)dep - (char *)hdr == be16_to_cpu(*ops->data_entry_tag_p(dep))); p += ops->data_entsize(dep->namelen); } } } /* * Initialize a data block at the given block number in the directory. * Give back the buffer for the created block. */ int /* error */ xfs_dir3_data_init( xfs_da_args_t *args, /* directory operation args */ xfs_dir2_db_t blkno, /* logical dir block number */ struct xfs_buf **bpp) /* output block buffer */ { struct xfs_buf *bp; /* block buffer */ xfs_dir2_data_hdr_t *hdr; /* data block header */ xfs_inode_t *dp; /* incore directory inode */ xfs_dir2_data_unused_t *dup; /* unused entry pointer */ struct xfs_dir2_data_free *bf; int error; /* error return value */ int i; /* bestfree index */ xfs_mount_t *mp; /* filesystem mount point */ xfs_trans_t *tp; /* transaction pointer */ int t; /* temp */ dp = args->dp; mp = dp->i_mount; tp = args->trans; /* * Get the buffer set up for the block. */ error = xfs_da_get_buf(tp, dp, xfs_dir2_db_to_da(args->geo, blkno), -1, &bp, XFS_DATA_FORK); if (error) return error; bp->b_ops = &xfs_dir3_data_buf_ops; xfs_trans_buf_set_type(tp, bp, XFS_BLFT_DIR_DATA_BUF); /* * Initialize the header. */ hdr = bp->b_addr; if (xfs_sb_version_hascrc(&mp->m_sb)) { struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr; memset(hdr3, 0, sizeof(*hdr3)); hdr3->magic = cpu_to_be32(XFS_DIR3_DATA_MAGIC); hdr3->blkno = cpu_to_be64(bp->b_bn); hdr3->owner = cpu_to_be64(dp->i_ino); uuid_copy(&hdr3->uuid, &mp->m_sb.sb_meta_uuid); } else hdr->magic = cpu_to_be32(XFS_DIR2_DATA_MAGIC); bf = dp->d_ops->data_bestfree_p(hdr); bf[0].offset = cpu_to_be16(dp->d_ops->data_entry_offset); for (i = 1; i < XFS_DIR2_DATA_FD_COUNT; i++) { bf[i].length = 0; bf[i].offset = 0; } /* * Set up an unused entry for the block's body. */ dup = dp->d_ops->data_unused_p(hdr); dup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG); t = args->geo->blksize - (uint)dp->d_ops->data_entry_offset; bf[0].length = cpu_to_be16(t); dup->length = cpu_to_be16(t); *xfs_dir2_data_unused_tag_p(dup) = cpu_to_be16((char *)dup - (char *)hdr); /* * Log it and return it. */ xfs_dir2_data_log_header(args, bp); xfs_dir2_data_log_unused(args, bp, dup); *bpp = bp; return 0; } /* * Log an active data entry from the block. */ void xfs_dir2_data_log_entry( struct xfs_da_args *args, struct xfs_buf *bp, xfs_dir2_data_entry_t *dep) /* data entry pointer */ { struct xfs_dir2_data_hdr *hdr = bp->b_addr; ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) || hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) || hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)); xfs_trans_log_buf(args->trans, bp, (uint)((char *)dep - (char *)hdr), (uint)((char *)(args->dp->d_ops->data_entry_tag_p(dep) + 1) - (char *)hdr - 1)); } /* * Log a data block header. */ void xfs_dir2_data_log_header( struct xfs_da_args *args, struct xfs_buf *bp) { #ifdef DEBUG struct xfs_dir2_data_hdr *hdr = bp->b_addr; ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) || hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) || hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)); #endif xfs_trans_log_buf(args->trans, bp, 0, args->dp->d_ops->data_entry_offset - 1); } /* * Log a data unused entry. */ void xfs_dir2_data_log_unused( struct xfs_da_args *args, struct xfs_buf *bp, xfs_dir2_data_unused_t *dup) /* data unused pointer */ { xfs_dir2_data_hdr_t *hdr = bp->b_addr; ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) || hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) || hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)); /* * Log the first part of the unused entry. */ xfs_trans_log_buf(args->trans, bp, (uint)((char *)dup - (char *)hdr), (uint)((char *)&dup->length + sizeof(dup->length) - 1 - (char *)hdr)); /* * Log the end (tag) of the unused entry. */ xfs_trans_log_buf(args->trans, bp, (uint)((char *)xfs_dir2_data_unused_tag_p(dup) - (char *)hdr), (uint)((char *)xfs_dir2_data_unused_tag_p(dup) - (char *)hdr + sizeof(xfs_dir2_data_off_t) - 1)); } /* * Make a byte range in the data block unused. * Its current contents are unimportant. */ void xfs_dir2_data_make_free( struct xfs_da_args *args, struct xfs_buf *bp, xfs_dir2_data_aoff_t offset, /* starting byte offset */ xfs_dir2_data_aoff_t len, /* length in bytes */ int *needlogp, /* out: log header */ int *needscanp) /* out: regen bestfree */ { xfs_dir2_data_hdr_t *hdr; /* data block pointer */ xfs_dir2_data_free_t *dfp; /* bestfree pointer */ char *endptr; /* end of data area */ int needscan; /* need to regen bestfree */ xfs_dir2_data_unused_t *newdup; /* new unused entry */ xfs_dir2_data_unused_t *postdup; /* unused entry after us */ xfs_dir2_data_unused_t *prevdup; /* unused entry before us */ struct xfs_dir2_data_free *bf; hdr = bp->b_addr; /* * Figure out where the end of the data area is. */ if (hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC)) endptr = (char *)hdr + args->geo->blksize; else { xfs_dir2_block_tail_t *btp; /* block tail */ ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) || hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)); btp = xfs_dir2_block_tail_p(args->geo, hdr); endptr = (char *)xfs_dir2_block_leaf_p(btp); } /* * If this isn't the start of the block, then back up to * the previous entry and see if it's free. */ if (offset > args->dp->d_ops->data_entry_offset) { __be16 *tagp; /* tag just before us */ tagp = (__be16 *)((char *)hdr + offset) - 1; prevdup = (xfs_dir2_data_unused_t *)((char *)hdr + be16_to_cpu(*tagp)); if (be16_to_cpu(prevdup->freetag) != XFS_DIR2_DATA_FREE_TAG) prevdup = NULL; } else prevdup = NULL; /* * If this isn't the end of the block, see if the entry after * us is free. */ if ((char *)hdr + offset + len < endptr) { postdup = (xfs_dir2_data_unused_t *)((char *)hdr + offset + len); if (be16_to_cpu(postdup->freetag) != XFS_DIR2_DATA_FREE_TAG) postdup = NULL; } else postdup = NULL; ASSERT(*needscanp == 0); needscan = 0; /* * Previous and following entries are both free, * merge everything into a single free entry. */ bf = args->dp->d_ops->data_bestfree_p(hdr); if (prevdup && postdup) { xfs_dir2_data_free_t *dfp2; /* another bestfree pointer */ /* * See if prevdup and/or postdup are in bestfree table. */ dfp = xfs_dir2_data_freefind(hdr, bf, prevdup); dfp2 = xfs_dir2_data_freefind(hdr, bf, postdup); /* * We need a rescan unless there are exactly 2 free entries * namely our two. Then we know what's happening, otherwise * since the third bestfree is there, there might be more * entries. */ needscan = (bf[2].length != 0); /* * Fix up the new big freespace. */ be16_add_cpu(&prevdup->length, len + be16_to_cpu(postdup->length)); *xfs_dir2_data_unused_tag_p(prevdup) = cpu_to_be16((char *)prevdup - (char *)hdr); xfs_dir2_data_log_unused(args, bp, prevdup); if (!needscan) { /* * Has to be the case that entries 0 and 1 are * dfp and dfp2 (don't know which is which), and * entry 2 is empty. * Remove entry 1 first then entry 0. */ ASSERT(dfp && dfp2); if (dfp == &bf[1]) { dfp = &bf[0]; ASSERT(dfp2 == dfp); dfp2 = &bf[1]; } xfs_dir2_data_freeremove(hdr, bf, dfp2, needlogp); xfs_dir2_data_freeremove(hdr, bf, dfp, needlogp); /* * Now insert the new entry. */ dfp = xfs_dir2_data_freeinsert(hdr, bf, prevdup, needlogp); ASSERT(dfp == &bf[0]); ASSERT(dfp->length == prevdup->length); ASSERT(!dfp[1].length); ASSERT(!dfp[2].length); } } /* * The entry before us is free, merge with it. */ else if (prevdup) { dfp = xfs_dir2_data_freefind(hdr, bf, prevdup); be16_add_cpu(&prevdup->length, len); *xfs_dir2_data_unused_tag_p(prevdup) = cpu_to_be16((char *)prevdup - (char *)hdr); xfs_dir2_data_log_unused(args, bp, prevdup); /* * If the previous entry was in the table, the new entry * is longer, so it will be in the table too. Remove * the old one and add the new one. */ if (dfp) { xfs_dir2_data_freeremove(hdr, bf, dfp, needlogp); xfs_dir2_data_freeinsert(hdr, bf, prevdup, needlogp); } /* * Otherwise we need a scan if the new entry is big enough. */ else { needscan = be16_to_cpu(prevdup->length) > be16_to_cpu(bf[2].length); } } /* * The following entry is free, merge with it. */ else if (postdup) { dfp = xfs_dir2_data_freefind(hdr, bf, postdup); newdup = (xfs_dir2_data_unused_t *)((char *)hdr + offset); newdup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG); newdup->length = cpu_to_be16(len + be16_to_cpu(postdup->length)); *xfs_dir2_data_unused_tag_p(newdup) = cpu_to_be16((char *)newdup - (char *)hdr); xfs_dir2_data_log_unused(args, bp, newdup); /* * If the following entry was in the table, the new entry * is longer, so it will be in the table too. Remove * the old one and add the new one. */ if (dfp) { xfs_dir2_data_freeremove(hdr, bf, dfp, needlogp); xfs_dir2_data_freeinsert(hdr, bf, newdup, needlogp); } /* * Otherwise we need a scan if the new entry is big enough. */ else { needscan = be16_to_cpu(newdup->length) > be16_to_cpu(bf[2].length); } } /* * Neither neighbor is free. Make a new entry. */ else { newdup = (xfs_dir2_data_unused_t *)((char *)hdr + offset); newdup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG); newdup->length = cpu_to_be16(len); *xfs_dir2_data_unused_tag_p(newdup) = cpu_to_be16((char *)newdup - (char *)hdr); xfs_dir2_data_log_unused(args, bp, newdup); xfs_dir2_data_freeinsert(hdr, bf, newdup, needlogp); } *needscanp = needscan; } /* * Take a byte range out of an existing unused space and make it un-free. */ void xfs_dir2_data_use_free( struct xfs_da_args *args, struct xfs_buf *bp, xfs_dir2_data_unused_t *dup, /* unused entry */ xfs_dir2_data_aoff_t offset, /* starting offset to use */ xfs_dir2_data_aoff_t len, /* length to use */ int *needlogp, /* out: need to log header */ int *needscanp) /* out: need regen bestfree */ { xfs_dir2_data_hdr_t *hdr; /* data block header */ xfs_dir2_data_free_t *dfp; /* bestfree pointer */ int matchback; /* matches end of freespace */ int matchfront; /* matches start of freespace */ int needscan; /* need to regen bestfree */ xfs_dir2_data_unused_t *newdup; /* new unused entry */ xfs_dir2_data_unused_t *newdup2; /* another new unused entry */ int oldlen; /* old unused entry's length */ struct xfs_dir2_data_free *bf; hdr = bp->b_addr; ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) || hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) || hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)); ASSERT(be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG); ASSERT(offset >= (char *)dup - (char *)hdr); ASSERT(offset + len <= (char *)dup + be16_to_cpu(dup->length) - (char *)hdr); ASSERT((char *)dup - (char *)hdr == be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup))); /* * Look up the entry in the bestfree table. */ oldlen = be16_to_cpu(dup->length); bf = args->dp->d_ops->data_bestfree_p(hdr); dfp = xfs_dir2_data_freefind(hdr, bf, dup); ASSERT(dfp || oldlen <= be16_to_cpu(bf[2].length)); /* * Check for alignment with front and back of the entry. */ matchfront = (char *)dup - (char *)hdr == offset; matchback = (char *)dup + oldlen - (char *)hdr == offset + len; ASSERT(*needscanp == 0); needscan = 0; /* * If we matched it exactly we just need to get rid of it from * the bestfree table. */ if (matchfront && matchback) { if (dfp) { needscan = (bf[2].offset != 0); if (!needscan) xfs_dir2_data_freeremove(hdr, bf, dfp, needlogp); } } /* * We match the first part of the entry. * Make a new entry with the remaining freespace. */ else if (matchfront) { newdup = (xfs_dir2_data_unused_t *)((char *)hdr + offset + len); newdup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG); newdup->length = cpu_to_be16(oldlen - len); *xfs_dir2_data_unused_tag_p(newdup) = cpu_to_be16((char *)newdup - (char *)hdr); xfs_dir2_data_log_unused(args, bp, newdup); /* * If it was in the table, remove it and add the new one. */ if (dfp) { xfs_dir2_data_freeremove(hdr, bf, dfp, needlogp); dfp = xfs_dir2_data_freeinsert(hdr, bf, newdup, needlogp); ASSERT(dfp != NULL); ASSERT(dfp->length == newdup->length); ASSERT(be16_to_cpu(dfp->offset) == (char *)newdup - (char *)hdr); /* * If we got inserted at the last slot, * that means we don't know if there was a better * choice for the last slot, or not. Rescan. */ needscan = dfp == &bf[2]; } } /* * We match the last part of the entry. * Trim the allocated space off the tail of the entry. */ else if (matchback) { newdup = dup; newdup->length = cpu_to_be16(((char *)hdr + offset) - (char *)newdup); *xfs_dir2_data_unused_tag_p(newdup) = cpu_to_be16((char *)newdup - (char *)hdr); xfs_dir2_data_log_unused(args, bp, newdup); /* * If it was in the table, remove it and add the new one. */ if (dfp) { xfs_dir2_data_freeremove(hdr, bf, dfp, needlogp); dfp = xfs_dir2_data_freeinsert(hdr, bf, newdup, needlogp); ASSERT(dfp != NULL); ASSERT(dfp->length == newdup->length); ASSERT(be16_to_cpu(dfp->offset) == (char *)newdup - (char *)hdr); /* * If we got inserted at the last slot, * that means we don't know if there was a better * choice for the last slot, or not. Rescan. */ needscan = dfp == &bf[2]; } } /* * Poking out the middle of an entry. * Make two new entries. */ else { newdup = dup; newdup->length = cpu_to_be16(((char *)hdr + offset) - (char *)newdup); *xfs_dir2_data_unused_tag_p(newdup) = cpu_to_be16((char *)newdup - (char *)hdr); xfs_dir2_data_log_unused(args, bp, newdup); newdup2 = (xfs_dir2_data_unused_t *)((char *)hdr + offset + len); newdup2->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG); newdup2->length = cpu_to_be16(oldlen - len - be16_to_cpu(newdup->length)); *xfs_dir2_data_unused_tag_p(newdup2) = cpu_to_be16((char *)newdup2 - (char *)hdr); xfs_dir2_data_log_unused(args, bp, newdup2); /* * If the old entry was in the table, we need to scan * if the 3rd entry was valid, since these entries * are smaller than the old one. * If we don't need to scan that means there were 1 or 2 * entries in the table, and removing the old and adding * the 2 new will work. */ if (dfp) { needscan = (bf[2].length != 0); if (!needscan) { xfs_dir2_data_freeremove(hdr, bf, dfp, needlogp); xfs_dir2_data_freeinsert(hdr, bf, newdup, needlogp); xfs_dir2_data_freeinsert(hdr, bf, newdup2, needlogp); } } } *needscanp = needscan; } partclone-0.2.86/src/xfs/xfs_dir2_leaf.c000066400000000000000000001432231262102574200200460ustar00rootroot00000000000000/* * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. * Copyright (c) 2013 Red Hat, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_mount.h" #include "xfs_da_format.h" #include "xfs_da_btree.h" #include "xfs_inode.h" #include "xfs_bmap.h" #include "xfs_dir2.h" #include "xfs_dir2_priv.h" #include "xfs_trace.h" #include "xfs_trans.h" #include "xfs_cksum.h" /* * Local function declarations. */ static int xfs_dir2_leaf_lookup_int(xfs_da_args_t *args, struct xfs_buf **lbpp, int *indexp, struct xfs_buf **dbpp); static void xfs_dir3_leaf_log_bests(struct xfs_da_args *args, struct xfs_buf *bp, int first, int last); static void xfs_dir3_leaf_log_tail(struct xfs_da_args *args, struct xfs_buf *bp); /* * Check the internal consistency of a leaf1 block. * Pop an assert if something is wrong. */ #ifdef DEBUG #define xfs_dir3_leaf_check(dp, bp) \ do { \ if (!xfs_dir3_leaf1_check((dp), (bp))) \ ASSERT(0); \ } while (0); STATIC bool xfs_dir3_leaf1_check( struct xfs_inode *dp, struct xfs_buf *bp) { struct xfs_dir2_leaf *leaf = bp->b_addr; struct xfs_dir3_icleaf_hdr leafhdr; dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf); if (leafhdr.magic == XFS_DIR3_LEAF1_MAGIC) { struct xfs_dir3_leaf_hdr *leaf3 = bp->b_addr; if (be64_to_cpu(leaf3->info.blkno) != bp->b_bn) return false; } else if (leafhdr.magic != XFS_DIR2_LEAF1_MAGIC) return false; return xfs_dir3_leaf_check_int(dp->i_mount, dp, &leafhdr, leaf); } #else #define xfs_dir3_leaf_check(dp, bp) #endif bool xfs_dir3_leaf_check_int( struct xfs_mount *mp, struct xfs_inode *dp, struct xfs_dir3_icleaf_hdr *hdr, struct xfs_dir2_leaf *leaf) { struct xfs_dir2_leaf_entry *ents; xfs_dir2_leaf_tail_t *ltp; int stale; int i; const struct xfs_dir_ops *ops; struct xfs_dir3_icleaf_hdr leafhdr; struct xfs_da_geometry *geo = mp->m_dir_geo; /* * we can be passed a null dp here from a verifier, so we need to go the * hard way to get them. */ ops = xfs_dir_get_ops(mp, dp); if (!hdr) { ops->leaf_hdr_from_disk(&leafhdr, leaf); hdr = &leafhdr; } ents = ops->leaf_ents_p(leaf); ltp = xfs_dir2_leaf_tail_p(geo, leaf); /* * XXX (dgc): This value is not restrictive enough. * Should factor in the size of the bests table as well. * We can deduce a value for that from di_size. */ if (hdr->count > ops->leaf_max_ents(geo)) return false; /* Leaves and bests don't overlap in leaf format. */ if ((hdr->magic == XFS_DIR2_LEAF1_MAGIC || hdr->magic == XFS_DIR3_LEAF1_MAGIC) && (char *)&ents[hdr->count] > (char *)xfs_dir2_leaf_bests_p(ltp)) return false; /* Check hash value order, count stale entries. */ for (i = stale = 0; i < hdr->count; i++) { if (i + 1 < hdr->count) { if (be32_to_cpu(ents[i].hashval) > be32_to_cpu(ents[i + 1].hashval)) return false; } if (ents[i].address == cpu_to_be32(XFS_DIR2_NULL_DATAPTR)) stale++; } if (hdr->stale != stale) return false; return true; } /* * We verify the magic numbers before decoding the leaf header so that on debug * kernels we don't get assertion failures in xfs_dir3_leaf_hdr_from_disk() due * to incorrect magic numbers. */ static bool xfs_dir3_leaf_verify( struct xfs_buf *bp, __uint16_t magic) { struct xfs_mount *mp = bp->b_target->bt_mount; struct xfs_dir2_leaf *leaf = bp->b_addr; ASSERT(magic == XFS_DIR2_LEAF1_MAGIC || magic == XFS_DIR2_LEAFN_MAGIC); if (xfs_sb_version_hascrc(&mp->m_sb)) { struct xfs_dir3_leaf_hdr *leaf3 = bp->b_addr; __uint16_t magic3; magic3 = (magic == XFS_DIR2_LEAF1_MAGIC) ? XFS_DIR3_LEAF1_MAGIC : XFS_DIR3_LEAFN_MAGIC; if (leaf3->info.hdr.magic != cpu_to_be16(magic3)) return false; if (!uuid_equal(&leaf3->info.uuid, &mp->m_sb.sb_meta_uuid)) return false; if (be64_to_cpu(leaf3->info.blkno) != bp->b_bn) return false; } else { if (leaf->hdr.info.magic != cpu_to_be16(magic)) return false; } return xfs_dir3_leaf_check_int(mp, NULL, NULL, leaf); } static void __read_verify( struct xfs_buf *bp, __uint16_t magic) { struct xfs_mount *mp = bp->b_target->bt_mount; if (xfs_sb_version_hascrc(&mp->m_sb) && !xfs_buf_verify_cksum(bp, XFS_DIR3_LEAF_CRC_OFF)) xfs_buf_ioerror(bp, -EFSBADCRC); else if (!xfs_dir3_leaf_verify(bp, magic)) xfs_buf_ioerror(bp, -EFSCORRUPTED); if (bp->b_error) xfs_verifier_error(bp); } static void __write_verify( struct xfs_buf *bp, __uint16_t magic) { struct xfs_mount *mp = bp->b_target->bt_mount; struct xfs_buf_log_item *bip = bp->b_fspriv; struct xfs_dir3_leaf_hdr *hdr3 = bp->b_addr; if (!xfs_dir3_leaf_verify(bp, magic)) { xfs_buf_ioerror(bp, -EFSCORRUPTED); xfs_verifier_error(bp); return; } if (!xfs_sb_version_hascrc(&mp->m_sb)) return; if (bip) hdr3->info.lsn = cpu_to_be64(bip->bli_item.li_lsn); xfs_buf_update_cksum(bp, XFS_DIR3_LEAF_CRC_OFF); } static void xfs_dir3_leaf1_read_verify( struct xfs_buf *bp) { __read_verify(bp, XFS_DIR2_LEAF1_MAGIC); } static void xfs_dir3_leaf1_write_verify( struct xfs_buf *bp) { __write_verify(bp, XFS_DIR2_LEAF1_MAGIC); } static void xfs_dir3_leafn_read_verify( struct xfs_buf *bp) { __read_verify(bp, XFS_DIR2_LEAFN_MAGIC); } static void xfs_dir3_leafn_write_verify( struct xfs_buf *bp) { __write_verify(bp, XFS_DIR2_LEAFN_MAGIC); } const struct xfs_buf_ops xfs_dir3_leaf1_buf_ops = { .verify_read = xfs_dir3_leaf1_read_verify, .verify_write = xfs_dir3_leaf1_write_verify, }; const struct xfs_buf_ops xfs_dir3_leafn_buf_ops = { .verify_read = xfs_dir3_leafn_read_verify, .verify_write = xfs_dir3_leafn_write_verify, }; static int xfs_dir3_leaf_read( struct xfs_trans *tp, struct xfs_inode *dp, xfs_dablk_t fbno, xfs_daddr_t mappedbno, struct xfs_buf **bpp) { int err; err = xfs_da_read_buf(tp, dp, fbno, mappedbno, bpp, XFS_DATA_FORK, &xfs_dir3_leaf1_buf_ops); if (!err && tp) xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_DIR_LEAF1_BUF); return err; } int xfs_dir3_leafn_read( struct xfs_trans *tp, struct xfs_inode *dp, xfs_dablk_t fbno, xfs_daddr_t mappedbno, struct xfs_buf **bpp) { int err; err = xfs_da_read_buf(tp, dp, fbno, mappedbno, bpp, XFS_DATA_FORK, &xfs_dir3_leafn_buf_ops); if (!err && tp) xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_DIR_LEAFN_BUF); return err; } /* * Initialize a new leaf block, leaf1 or leafn magic accepted. */ static void xfs_dir3_leaf_init( struct xfs_mount *mp, struct xfs_trans *tp, struct xfs_buf *bp, xfs_ino_t owner, __uint16_t type) { struct xfs_dir2_leaf *leaf = bp->b_addr; ASSERT(type == XFS_DIR2_LEAF1_MAGIC || type == XFS_DIR2_LEAFN_MAGIC); if (xfs_sb_version_hascrc(&mp->m_sb)) { struct xfs_dir3_leaf_hdr *leaf3 = bp->b_addr; memset(leaf3, 0, sizeof(*leaf3)); leaf3->info.hdr.magic = (type == XFS_DIR2_LEAF1_MAGIC) ? cpu_to_be16(XFS_DIR3_LEAF1_MAGIC) : cpu_to_be16(XFS_DIR3_LEAFN_MAGIC); leaf3->info.blkno = cpu_to_be64(bp->b_bn); leaf3->info.owner = cpu_to_be64(owner); uuid_copy(&leaf3->info.uuid, &mp->m_sb.sb_meta_uuid); } else { memset(leaf, 0, sizeof(*leaf)); leaf->hdr.info.magic = cpu_to_be16(type); } /* * If it's a leaf-format directory initialize the tail. * Caller is responsible for initialising the bests table. */ if (type == XFS_DIR2_LEAF1_MAGIC) { struct xfs_dir2_leaf_tail *ltp; ltp = xfs_dir2_leaf_tail_p(mp->m_dir_geo, leaf); ltp->bestcount = 0; bp->b_ops = &xfs_dir3_leaf1_buf_ops; xfs_trans_buf_set_type(tp, bp, XFS_BLFT_DIR_LEAF1_BUF); } else { bp->b_ops = &xfs_dir3_leafn_buf_ops; xfs_trans_buf_set_type(tp, bp, XFS_BLFT_DIR_LEAFN_BUF); } } int xfs_dir3_leaf_get_buf( xfs_da_args_t *args, xfs_dir2_db_t bno, struct xfs_buf **bpp, __uint16_t magic) { struct xfs_inode *dp = args->dp; struct xfs_trans *tp = args->trans; struct xfs_mount *mp = dp->i_mount; struct xfs_buf *bp; int error; ASSERT(magic == XFS_DIR2_LEAF1_MAGIC || magic == XFS_DIR2_LEAFN_MAGIC); ASSERT(bno >= xfs_dir2_byte_to_db(args->geo, XFS_DIR2_LEAF_OFFSET) && bno < xfs_dir2_byte_to_db(args->geo, XFS_DIR2_FREE_OFFSET)); error = xfs_da_get_buf(tp, dp, xfs_dir2_db_to_da(args->geo, bno), -1, &bp, XFS_DATA_FORK); if (error) return error; xfs_dir3_leaf_init(mp, tp, bp, dp->i_ino, magic); xfs_dir3_leaf_log_header(args, bp); if (magic == XFS_DIR2_LEAF1_MAGIC) xfs_dir3_leaf_log_tail(args, bp); *bpp = bp; return 0; } /* * Convert a block form directory to a leaf form directory. */ int /* error */ xfs_dir2_block_to_leaf( xfs_da_args_t *args, /* operation arguments */ struct xfs_buf *dbp) /* input block's buffer */ { __be16 *bestsp; /* leaf's bestsp entries */ xfs_dablk_t blkno; /* leaf block's bno */ xfs_dir2_data_hdr_t *hdr; /* block header */ xfs_dir2_leaf_entry_t *blp; /* block's leaf entries */ xfs_dir2_block_tail_t *btp; /* block's tail */ xfs_inode_t *dp; /* incore directory inode */ int error; /* error return code */ struct xfs_buf *lbp; /* leaf block's buffer */ xfs_dir2_db_t ldb; /* leaf block's bno */ xfs_dir2_leaf_t *leaf; /* leaf structure */ xfs_dir2_leaf_tail_t *ltp; /* leaf's tail */ int needlog; /* need to log block header */ int needscan; /* need to rescan bestfree */ xfs_trans_t *tp; /* transaction pointer */ struct xfs_dir2_data_free *bf; struct xfs_dir2_leaf_entry *ents; struct xfs_dir3_icleaf_hdr leafhdr; trace_xfs_dir2_block_to_leaf(args); dp = args->dp; tp = args->trans; /* * Add the leaf block to the inode. * This interface will only put blocks in the leaf/node range. * Since that's empty now, we'll get the root (block 0 in range). */ if ((error = xfs_da_grow_inode(args, &blkno))) { return error; } ldb = xfs_dir2_da_to_db(args->geo, blkno); ASSERT(ldb == xfs_dir2_byte_to_db(args->geo, XFS_DIR2_LEAF_OFFSET)); /* * Initialize the leaf block, get a buffer for it. */ error = xfs_dir3_leaf_get_buf(args, ldb, &lbp, XFS_DIR2_LEAF1_MAGIC); if (error) return error; leaf = lbp->b_addr; hdr = dbp->b_addr; xfs_dir3_data_check(dp, dbp); btp = xfs_dir2_block_tail_p(args->geo, hdr); blp = xfs_dir2_block_leaf_p(btp); bf = dp->d_ops->data_bestfree_p(hdr); ents = dp->d_ops->leaf_ents_p(leaf); /* * Set the counts in the leaf header. */ dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf); leafhdr.count = be32_to_cpu(btp->count); leafhdr.stale = be32_to_cpu(btp->stale); dp->d_ops->leaf_hdr_to_disk(leaf, &leafhdr); xfs_dir3_leaf_log_header(args, lbp); /* * Could compact these but I think we always do the conversion * after squeezing out stale entries. */ memcpy(ents, blp, be32_to_cpu(btp->count) * sizeof(xfs_dir2_leaf_entry_t)); xfs_dir3_leaf_log_ents(args, lbp, 0, leafhdr.count - 1); needscan = 0; needlog = 1; /* * Make the space formerly occupied by the leaf entries and block * tail be free. */ xfs_dir2_data_make_free(args, dbp, (xfs_dir2_data_aoff_t)((char *)blp - (char *)hdr), (xfs_dir2_data_aoff_t)((char *)hdr + args->geo->blksize - (char *)blp), &needlog, &needscan); /* * Fix up the block header, make it a data block. */ dbp->b_ops = &xfs_dir3_data_buf_ops; xfs_trans_buf_set_type(tp, dbp, XFS_BLFT_DIR_DATA_BUF); if (hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC)) hdr->magic = cpu_to_be32(XFS_DIR2_DATA_MAGIC); else hdr->magic = cpu_to_be32(XFS_DIR3_DATA_MAGIC); if (needscan) xfs_dir2_data_freescan(dp, hdr, &needlog); /* * Set up leaf tail and bests table. */ ltp = xfs_dir2_leaf_tail_p(args->geo, leaf); ltp->bestcount = cpu_to_be32(1); bestsp = xfs_dir2_leaf_bests_p(ltp); bestsp[0] = bf[0].length; /* * Log the data header and leaf bests table. */ if (needlog) xfs_dir2_data_log_header(args, dbp); xfs_dir3_leaf_check(dp, lbp); xfs_dir3_data_check(dp, dbp); xfs_dir3_leaf_log_bests(args, lbp, 0, 0); return 0; } STATIC void xfs_dir3_leaf_find_stale( struct xfs_dir3_icleaf_hdr *leafhdr, struct xfs_dir2_leaf_entry *ents, int index, int *lowstale, int *highstale) { /* * Find the first stale entry before our index, if any. */ for (*lowstale = index - 1; *lowstale >= 0; --*lowstale) { if (ents[*lowstale].address == cpu_to_be32(XFS_DIR2_NULL_DATAPTR)) break; } /* * Find the first stale entry at or after our index, if any. * Stop if the result would require moving more entries than using * lowstale. */ for (*highstale = index; *highstale < leafhdr->count; ++*highstale) { if (ents[*highstale].address == cpu_to_be32(XFS_DIR2_NULL_DATAPTR)) break; if (*lowstale >= 0 && index - *lowstale <= *highstale - index) break; } } struct xfs_dir2_leaf_entry * xfs_dir3_leaf_find_entry( struct xfs_dir3_icleaf_hdr *leafhdr, struct xfs_dir2_leaf_entry *ents, int index, /* leaf table position */ int compact, /* need to compact leaves */ int lowstale, /* index of prev stale leaf */ int highstale, /* index of next stale leaf */ int *lfloglow, /* low leaf logging index */ int *lfloghigh) /* high leaf logging index */ { if (!leafhdr->stale) { xfs_dir2_leaf_entry_t *lep; /* leaf entry table pointer */ /* * Now we need to make room to insert the leaf entry. * * If there are no stale entries, just insert a hole at index. */ lep = &ents[index]; if (index < leafhdr->count) memmove(lep + 1, lep, (leafhdr->count - index) * sizeof(*lep)); /* * Record low and high logging indices for the leaf. */ *lfloglow = index; *lfloghigh = leafhdr->count++; return lep; } /* * There are stale entries. * * We will use one of them for the new entry. It's probably not at * the right location, so we'll have to shift some up or down first. * * If we didn't compact before, we need to find the nearest stale * entries before and after our insertion point. */ if (compact == 0) xfs_dir3_leaf_find_stale(leafhdr, ents, index, &lowstale, &highstale); /* * If the low one is better, use it. */ if (lowstale >= 0 && (highstale == leafhdr->count || index - lowstale - 1 < highstale - index)) { ASSERT(index - lowstale - 1 >= 0); ASSERT(ents[lowstale].address == cpu_to_be32(XFS_DIR2_NULL_DATAPTR)); /* * Copy entries up to cover the stale entry and make room * for the new entry. */ if (index - lowstale - 1 > 0) { memmove(&ents[lowstale], &ents[lowstale + 1], (index - lowstale - 1) * sizeof(xfs_dir2_leaf_entry_t)); } *lfloglow = MIN(lowstale, *lfloglow); *lfloghigh = MAX(index - 1, *lfloghigh); leafhdr->stale--; return &ents[index - 1]; } /* * The high one is better, so use that one. */ ASSERT(highstale - index >= 0); ASSERT(ents[highstale].address == cpu_to_be32(XFS_DIR2_NULL_DATAPTR)); /* * Copy entries down to cover the stale entry and make room for the * new entry. */ if (highstale - index > 0) { memmove(&ents[index + 1], &ents[index], (highstale - index) * sizeof(xfs_dir2_leaf_entry_t)); } *lfloglow = MIN(index, *lfloglow); *lfloghigh = MAX(highstale, *lfloghigh); leafhdr->stale--; return &ents[index]; } /* * Add an entry to a leaf form directory. */ int /* error */ xfs_dir2_leaf_addname( xfs_da_args_t *args) /* operation arguments */ { __be16 *bestsp; /* freespace table in leaf */ int compact; /* need to compact leaves */ xfs_dir2_data_hdr_t *hdr; /* data block header */ struct xfs_buf *dbp; /* data block buffer */ xfs_dir2_data_entry_t *dep; /* data block entry */ xfs_inode_t *dp; /* incore directory inode */ xfs_dir2_data_unused_t *dup; /* data unused entry */ int error; /* error return value */ int grown; /* allocated new data block */ int highstale; /* index of next stale leaf */ int i; /* temporary, index */ int index; /* leaf table position */ struct xfs_buf *lbp; /* leaf's buffer */ xfs_dir2_leaf_t *leaf; /* leaf structure */ int length; /* length of new entry */ xfs_dir2_leaf_entry_t *lep; /* leaf entry table pointer */ int lfloglow; /* low leaf logging index */ int lfloghigh; /* high leaf logging index */ int lowstale; /* index of prev stale leaf */ xfs_dir2_leaf_tail_t *ltp; /* leaf tail pointer */ int needbytes; /* leaf block bytes needed */ int needlog; /* need to log data header */ int needscan; /* need to rescan data free */ __be16 *tagp; /* end of data entry */ xfs_trans_t *tp; /* transaction pointer */ xfs_dir2_db_t use_block; /* data block number */ struct xfs_dir2_data_free *bf; /* bestfree table */ struct xfs_dir2_leaf_entry *ents; struct xfs_dir3_icleaf_hdr leafhdr; trace_xfs_dir2_leaf_addname(args); dp = args->dp; tp = args->trans; error = xfs_dir3_leaf_read(tp, dp, args->geo->leafblk, -1, &lbp); if (error) return error; /* * Look up the entry by hash value and name. * We know it's not there, our caller has already done a lookup. * So the index is of the entry to insert in front of. * But if there are dup hash values the index is of the first of those. */ index = xfs_dir2_leaf_search_hash(args, lbp); leaf = lbp->b_addr; ltp = xfs_dir2_leaf_tail_p(args->geo, leaf); ents = dp->d_ops->leaf_ents_p(leaf); dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf); bestsp = xfs_dir2_leaf_bests_p(ltp); length = dp->d_ops->data_entsize(args->namelen); /* * See if there are any entries with the same hash value * and space in their block for the new entry. * This is good because it puts multiple same-hash value entries * in a data block, improving the lookup of those entries. */ for (use_block = -1, lep = &ents[index]; index < leafhdr.count && be32_to_cpu(lep->hashval) == args->hashval; index++, lep++) { if (be32_to_cpu(lep->address) == XFS_DIR2_NULL_DATAPTR) continue; i = xfs_dir2_dataptr_to_db(args->geo, be32_to_cpu(lep->address)); ASSERT(i < be32_to_cpu(ltp->bestcount)); ASSERT(bestsp[i] != cpu_to_be16(NULLDATAOFF)); if (be16_to_cpu(bestsp[i]) >= length) { use_block = i; break; } } /* * Didn't find a block yet, linear search all the data blocks. */ if (use_block == -1) { for (i = 0; i < be32_to_cpu(ltp->bestcount); i++) { /* * Remember a block we see that's missing. */ if (bestsp[i] == cpu_to_be16(NULLDATAOFF) && use_block == -1) use_block = i; else if (be16_to_cpu(bestsp[i]) >= length) { use_block = i; break; } } } /* * How many bytes do we need in the leaf block? */ needbytes = 0; if (!leafhdr.stale) needbytes += sizeof(xfs_dir2_leaf_entry_t); if (use_block == -1) needbytes += sizeof(xfs_dir2_data_off_t); /* * Now kill use_block if it refers to a missing block, so we * can use it as an indication of allocation needed. */ if (use_block != -1 && bestsp[use_block] == cpu_to_be16(NULLDATAOFF)) use_block = -1; /* * If we don't have enough free bytes but we can make enough * by compacting out stale entries, we'll do that. */ if ((char *)bestsp - (char *)&ents[leafhdr.count] < needbytes && leafhdr.stale > 1) compact = 1; /* * Otherwise if we don't have enough free bytes we need to * convert to node form. */ else if ((char *)bestsp - (char *)&ents[leafhdr.count] < needbytes) { /* * Just checking or no space reservation, give up. */ if ((args->op_flags & XFS_DA_OP_JUSTCHECK) || args->total == 0) { xfs_trans_brelse(tp, lbp); return -ENOSPC; } /* * Convert to node form. */ error = xfs_dir2_leaf_to_node(args, lbp); if (error) return error; /* * Then add the new entry. */ return xfs_dir2_node_addname(args); } /* * Otherwise it will fit without compaction. */ else compact = 0; /* * If just checking, then it will fit unless we needed to allocate * a new data block. */ if (args->op_flags & XFS_DA_OP_JUSTCHECK) { xfs_trans_brelse(tp, lbp); return use_block == -1 ? -ENOSPC : 0; } /* * If no allocations are allowed, return now before we've * changed anything. */ if (args->total == 0 && use_block == -1) { xfs_trans_brelse(tp, lbp); return -ENOSPC; } /* * Need to compact the leaf entries, removing stale ones. * Leave one stale entry behind - the one closest to our * insertion index - and we'll shift that one to our insertion * point later. */ if (compact) { xfs_dir3_leaf_compact_x1(&leafhdr, ents, &index, &lowstale, &highstale, &lfloglow, &lfloghigh); } /* * There are stale entries, so we'll need log-low and log-high * impossibly bad values later. */ else if (leafhdr.stale) { lfloglow = leafhdr.count; lfloghigh = -1; } /* * If there was no data block space found, we need to allocate * a new one. */ if (use_block == -1) { /* * Add the new data block. */ if ((error = xfs_dir2_grow_inode(args, XFS_DIR2_DATA_SPACE, &use_block))) { xfs_trans_brelse(tp, lbp); return error; } /* * Initialize the block. */ if ((error = xfs_dir3_data_init(args, use_block, &dbp))) { xfs_trans_brelse(tp, lbp); return error; } /* * If we're adding a new data block on the end we need to * extend the bests table. Copy it up one entry. */ if (use_block >= be32_to_cpu(ltp->bestcount)) { bestsp--; memmove(&bestsp[0], &bestsp[1], be32_to_cpu(ltp->bestcount) * sizeof(bestsp[0])); be32_add_cpu(<p->bestcount, 1); xfs_dir3_leaf_log_tail(args, lbp); xfs_dir3_leaf_log_bests(args, lbp, 0, be32_to_cpu(ltp->bestcount) - 1); } /* * If we're filling in a previously empty block just log it. */ else xfs_dir3_leaf_log_bests(args, lbp, use_block, use_block); hdr = dbp->b_addr; bf = dp->d_ops->data_bestfree_p(hdr); bestsp[use_block] = bf[0].length; grown = 1; } else { /* * Already had space in some data block. * Just read that one in. */ error = xfs_dir3_data_read(tp, dp, xfs_dir2_db_to_da(args->geo, use_block), -1, &dbp); if (error) { xfs_trans_brelse(tp, lbp); return error; } hdr = dbp->b_addr; bf = dp->d_ops->data_bestfree_p(hdr); grown = 0; } /* * Point to the biggest freespace in our data block. */ dup = (xfs_dir2_data_unused_t *) ((char *)hdr + be16_to_cpu(bf[0].offset)); ASSERT(be16_to_cpu(dup->length) >= length); needscan = needlog = 0; /* * Mark the initial part of our freespace in use for the new entry. */ xfs_dir2_data_use_free(args, dbp, dup, (xfs_dir2_data_aoff_t)((char *)dup - (char *)hdr), length, &needlog, &needscan); /* * Initialize our new entry (at last). */ dep = (xfs_dir2_data_entry_t *)dup; dep->inumber = cpu_to_be64(args->inumber); dep->namelen = args->namelen; memcpy(dep->name, args->name, dep->namelen); dp->d_ops->data_put_ftype(dep, args->filetype); tagp = dp->d_ops->data_entry_tag_p(dep); *tagp = cpu_to_be16((char *)dep - (char *)hdr); /* * Need to scan fix up the bestfree table. */ if (needscan) xfs_dir2_data_freescan(dp, hdr, &needlog); /* * Need to log the data block's header. */ if (needlog) xfs_dir2_data_log_header(args, dbp); xfs_dir2_data_log_entry(args, dbp, dep); /* * If the bests table needs to be changed, do it. * Log the change unless we've already done that. */ if (be16_to_cpu(bestsp[use_block]) != be16_to_cpu(bf[0].length)) { bestsp[use_block] = bf[0].length; if (!grown) xfs_dir3_leaf_log_bests(args, lbp, use_block, use_block); } lep = xfs_dir3_leaf_find_entry(&leafhdr, ents, index, compact, lowstale, highstale, &lfloglow, &lfloghigh); /* * Fill in the new leaf entry. */ lep->hashval = cpu_to_be32(args->hashval); lep->address = cpu_to_be32( xfs_dir2_db_off_to_dataptr(args->geo, use_block, be16_to_cpu(*tagp))); /* * Log the leaf fields and give up the buffers. */ dp->d_ops->leaf_hdr_to_disk(leaf, &leafhdr); xfs_dir3_leaf_log_header(args, lbp); xfs_dir3_leaf_log_ents(args, lbp, lfloglow, lfloghigh); xfs_dir3_leaf_check(dp, lbp); xfs_dir3_data_check(dp, dbp); return 0; } /* * Compact out any stale entries in the leaf. * Log the header and changed leaf entries, if any. */ void xfs_dir3_leaf_compact( xfs_da_args_t *args, /* operation arguments */ struct xfs_dir3_icleaf_hdr *leafhdr, struct xfs_buf *bp) /* leaf buffer */ { int from; /* source leaf index */ xfs_dir2_leaf_t *leaf; /* leaf structure */ int loglow; /* first leaf entry to log */ int to; /* target leaf index */ struct xfs_dir2_leaf_entry *ents; struct xfs_inode *dp = args->dp; leaf = bp->b_addr; if (!leafhdr->stale) return; /* * Compress out the stale entries in place. */ ents = dp->d_ops->leaf_ents_p(leaf); for (from = to = 0, loglow = -1; from < leafhdr->count; from++) { if (ents[from].address == cpu_to_be32(XFS_DIR2_NULL_DATAPTR)) continue; /* * Only actually copy the entries that are different. */ if (from > to) { if (loglow == -1) loglow = to; ents[to] = ents[from]; } to++; } /* * Update and log the header, log the leaf entries. */ ASSERT(leafhdr->stale == from - to); leafhdr->count -= leafhdr->stale; leafhdr->stale = 0; dp->d_ops->leaf_hdr_to_disk(leaf, leafhdr); xfs_dir3_leaf_log_header(args, bp); if (loglow != -1) xfs_dir3_leaf_log_ents(args, bp, loglow, to - 1); } /* * Compact the leaf entries, removing stale ones. * Leave one stale entry behind - the one closest to our * insertion index - and the caller will shift that one to our insertion * point later. * Return new insertion index, where the remaining stale entry is, * and leaf logging indices. */ void xfs_dir3_leaf_compact_x1( struct xfs_dir3_icleaf_hdr *leafhdr, struct xfs_dir2_leaf_entry *ents, int *indexp, /* insertion index */ int *lowstalep, /* out: stale entry before us */ int *highstalep, /* out: stale entry after us */ int *lowlogp, /* out: low log index */ int *highlogp) /* out: high log index */ { int from; /* source copy index */ int highstale; /* stale entry at/after index */ int index; /* insertion index */ int keepstale; /* source index of kept stale */ int lowstale; /* stale entry before index */ int newindex=0; /* new insertion index */ int to; /* destination copy index */ ASSERT(leafhdr->stale > 1); index = *indexp; xfs_dir3_leaf_find_stale(leafhdr, ents, index, &lowstale, &highstale); /* * Pick the better of lowstale and highstale. */ if (lowstale >= 0 && (highstale == leafhdr->count || index - lowstale <= highstale - index)) keepstale = lowstale; else keepstale = highstale; /* * Copy the entries in place, removing all the stale entries * except keepstale. */ for (from = to = 0; from < leafhdr->count; from++) { /* * Notice the new value of index. */ if (index == from) newindex = to; if (from != keepstale && ents[from].address == cpu_to_be32(XFS_DIR2_NULL_DATAPTR)) { if (from == to) *lowlogp = to; continue; } /* * Record the new keepstale value for the insertion. */ if (from == keepstale) lowstale = highstale = to; /* * Copy only the entries that have moved. */ if (from > to) ents[to] = ents[from]; to++; } ASSERT(from > to); /* * If the insertion point was past the last entry, * set the new insertion point accordingly. */ if (index == from) newindex = to; *indexp = newindex; /* * Adjust the leaf header values. */ leafhdr->count -= from - to; leafhdr->stale = 1; /* * Remember the low/high stale value only in the "right" * direction. */ if (lowstale >= newindex) lowstale = -1; else highstale = leafhdr->count; *highlogp = leafhdr->count - 1; *lowstalep = lowstale; *highstalep = highstale; } /* * Log the bests entries indicated from a leaf1 block. */ static void xfs_dir3_leaf_log_bests( struct xfs_da_args *args, struct xfs_buf *bp, /* leaf buffer */ int first, /* first entry to log */ int last) /* last entry to log */ { __be16 *firstb; /* pointer to first entry */ __be16 *lastb; /* pointer to last entry */ struct xfs_dir2_leaf *leaf = bp->b_addr; xfs_dir2_leaf_tail_t *ltp; /* leaf tail structure */ ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAF1_MAGIC) || leaf->hdr.info.magic == cpu_to_be16(XFS_DIR3_LEAF1_MAGIC)); ltp = xfs_dir2_leaf_tail_p(args->geo, leaf); firstb = xfs_dir2_leaf_bests_p(ltp) + first; lastb = xfs_dir2_leaf_bests_p(ltp) + last; xfs_trans_log_buf(args->trans, bp, (uint)((char *)firstb - (char *)leaf), (uint)((char *)lastb - (char *)leaf + sizeof(*lastb) - 1)); } /* * Log the leaf entries indicated from a leaf1 or leafn block. */ void xfs_dir3_leaf_log_ents( struct xfs_da_args *args, struct xfs_buf *bp, int first, int last) { xfs_dir2_leaf_entry_t *firstlep; /* pointer to first entry */ xfs_dir2_leaf_entry_t *lastlep; /* pointer to last entry */ struct xfs_dir2_leaf *leaf = bp->b_addr; struct xfs_dir2_leaf_entry *ents; ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAF1_MAGIC) || leaf->hdr.info.magic == cpu_to_be16(XFS_DIR3_LEAF1_MAGIC) || leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC) || leaf->hdr.info.magic == cpu_to_be16(XFS_DIR3_LEAFN_MAGIC)); ents = args->dp->d_ops->leaf_ents_p(leaf); firstlep = &ents[first]; lastlep = &ents[last]; xfs_trans_log_buf(args->trans, bp, (uint)((char *)firstlep - (char *)leaf), (uint)((char *)lastlep - (char *)leaf + sizeof(*lastlep) - 1)); } /* * Log the header of the leaf1 or leafn block. */ void xfs_dir3_leaf_log_header( struct xfs_da_args *args, struct xfs_buf *bp) { struct xfs_dir2_leaf *leaf = bp->b_addr; ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAF1_MAGIC) || leaf->hdr.info.magic == cpu_to_be16(XFS_DIR3_LEAF1_MAGIC) || leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC) || leaf->hdr.info.magic == cpu_to_be16(XFS_DIR3_LEAFN_MAGIC)); xfs_trans_log_buf(args->trans, bp, (uint)((char *)&leaf->hdr - (char *)leaf), args->dp->d_ops->leaf_hdr_size - 1); } /* * Log the tail of the leaf1 block. */ STATIC void xfs_dir3_leaf_log_tail( struct xfs_da_args *args, struct xfs_buf *bp) { struct xfs_dir2_leaf *leaf = bp->b_addr; xfs_dir2_leaf_tail_t *ltp; /* leaf tail structure */ ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAF1_MAGIC) || leaf->hdr.info.magic == cpu_to_be16(XFS_DIR3_LEAF1_MAGIC) || leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC) || leaf->hdr.info.magic == cpu_to_be16(XFS_DIR3_LEAFN_MAGIC)); ltp = xfs_dir2_leaf_tail_p(args->geo, leaf); xfs_trans_log_buf(args->trans, bp, (uint)((char *)ltp - (char *)leaf), (uint)(args->geo->blksize - 1)); } /* * Look up the entry referred to by args in the leaf format directory. * Most of the work is done by the xfs_dir2_leaf_lookup_int routine which * is also used by the node-format code. */ int xfs_dir2_leaf_lookup( xfs_da_args_t *args) /* operation arguments */ { struct xfs_buf *dbp; /* data block buffer */ xfs_dir2_data_entry_t *dep; /* data block entry */ xfs_inode_t *dp; /* incore directory inode */ int error; /* error return code */ int index; /* found entry index */ struct xfs_buf *lbp; /* leaf buffer */ xfs_dir2_leaf_t *leaf; /* leaf structure */ xfs_dir2_leaf_entry_t *lep; /* leaf entry */ xfs_trans_t *tp; /* transaction pointer */ struct xfs_dir2_leaf_entry *ents; trace_xfs_dir2_leaf_lookup(args); /* * Look up name in the leaf block, returning both buffers and index. */ if ((error = xfs_dir2_leaf_lookup_int(args, &lbp, &index, &dbp))) { return error; } tp = args->trans; dp = args->dp; xfs_dir3_leaf_check(dp, lbp); leaf = lbp->b_addr; ents = dp->d_ops->leaf_ents_p(leaf); /* * Get to the leaf entry and contained data entry address. */ lep = &ents[index]; /* * Point to the data entry. */ dep = (xfs_dir2_data_entry_t *) ((char *)dbp->b_addr + xfs_dir2_dataptr_to_off(args->geo, be32_to_cpu(lep->address))); /* * Return the found inode number & CI name if appropriate */ args->inumber = be64_to_cpu(dep->inumber); args->filetype = dp->d_ops->data_get_ftype(dep); error = xfs_dir_cilookup_result(args, dep->name, dep->namelen); xfs_trans_brelse(tp, dbp); xfs_trans_brelse(tp, lbp); return error; } /* * Look up name/hash in the leaf block. * Fill in indexp with the found index, and dbpp with the data buffer. * If not found dbpp will be NULL, and ENOENT comes back. * lbpp will always be filled in with the leaf buffer unless there's an error. */ static int /* error */ xfs_dir2_leaf_lookup_int( xfs_da_args_t *args, /* operation arguments */ struct xfs_buf **lbpp, /* out: leaf buffer */ int *indexp, /* out: index in leaf block */ struct xfs_buf **dbpp) /* out: data buffer */ { xfs_dir2_db_t curdb = -1; /* current data block number */ struct xfs_buf *dbp = NULL; /* data buffer */ xfs_dir2_data_entry_t *dep; /* data entry */ xfs_inode_t *dp; /* incore directory inode */ int error; /* error return code */ int index; /* index in leaf block */ struct xfs_buf *lbp; /* leaf buffer */ xfs_dir2_leaf_entry_t *lep; /* leaf entry */ xfs_dir2_leaf_t *leaf; /* leaf structure */ xfs_mount_t *mp; /* filesystem mount point */ xfs_dir2_db_t newdb; /* new data block number */ xfs_trans_t *tp; /* transaction pointer */ xfs_dir2_db_t cidb = -1; /* case match data block no. */ enum xfs_dacmp cmp; /* name compare result */ struct xfs_dir2_leaf_entry *ents; struct xfs_dir3_icleaf_hdr leafhdr; dp = args->dp; tp = args->trans; mp = dp->i_mount; error = xfs_dir3_leaf_read(tp, dp, args->geo->leafblk, -1, &lbp); if (error) return error; *lbpp = lbp; leaf = lbp->b_addr; xfs_dir3_leaf_check(dp, lbp); ents = dp->d_ops->leaf_ents_p(leaf); dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf); /* * Look for the first leaf entry with our hash value. */ index = xfs_dir2_leaf_search_hash(args, lbp); /* * Loop over all the entries with the right hash value * looking to match the name. */ for (lep = &ents[index]; index < leafhdr.count && be32_to_cpu(lep->hashval) == args->hashval; lep++, index++) { /* * Skip over stale leaf entries. */ if (be32_to_cpu(lep->address) == XFS_DIR2_NULL_DATAPTR) continue; /* * Get the new data block number. */ newdb = xfs_dir2_dataptr_to_db(args->geo, be32_to_cpu(lep->address)); /* * If it's not the same as the old data block number, * need to pitch the old one and read the new one. */ if (newdb != curdb) { if (dbp) xfs_trans_brelse(tp, dbp); error = xfs_dir3_data_read(tp, dp, xfs_dir2_db_to_da(args->geo, newdb), -1, &dbp); if (error) { xfs_trans_brelse(tp, lbp); return error; } curdb = newdb; } /* * Point to the data entry. */ dep = (xfs_dir2_data_entry_t *)((char *)dbp->b_addr + xfs_dir2_dataptr_to_off(args->geo, be32_to_cpu(lep->address))); /* * Compare name and if it's an exact match, return the index * and buffer. If it's the first case-insensitive match, store * the index and buffer and continue looking for an exact match. */ cmp = mp->m_dirnameops->compname(args, dep->name, dep->namelen); if (cmp != XFS_CMP_DIFFERENT && cmp != args->cmpresult) { args->cmpresult = cmp; *indexp = index; /* case exact match: return the current buffer. */ if (cmp == XFS_CMP_EXACT) { *dbpp = dbp; return 0; } cidb = curdb; } } ASSERT(args->op_flags & XFS_DA_OP_OKNOENT); /* * Here, we can only be doing a lookup (not a rename or remove). * If a case-insensitive match was found earlier, re-read the * appropriate data block if required and return it. */ if (args->cmpresult == XFS_CMP_CASE) { ASSERT(cidb != -1); if (cidb != curdb) { xfs_trans_brelse(tp, dbp); error = xfs_dir3_data_read(tp, dp, xfs_dir2_db_to_da(args->geo, cidb), -1, &dbp); if (error) { xfs_trans_brelse(tp, lbp); return error; } } *dbpp = dbp; return 0; } /* * No match found, return -ENOENT. */ ASSERT(cidb == -1); if (dbp) xfs_trans_brelse(tp, dbp); xfs_trans_brelse(tp, lbp); return -ENOENT; } /* * Remove an entry from a leaf format directory. */ int /* error */ xfs_dir2_leaf_removename( xfs_da_args_t *args) /* operation arguments */ { __be16 *bestsp; /* leaf block best freespace */ xfs_dir2_data_hdr_t *hdr; /* data block header */ xfs_dir2_db_t db; /* data block number */ struct xfs_buf *dbp; /* data block buffer */ xfs_dir2_data_entry_t *dep; /* data entry structure */ xfs_inode_t *dp; /* incore directory inode */ int error; /* error return code */ xfs_dir2_db_t i; /* temporary data block # */ int index; /* index into leaf entries */ struct xfs_buf *lbp; /* leaf buffer */ xfs_dir2_leaf_t *leaf; /* leaf structure */ xfs_dir2_leaf_entry_t *lep; /* leaf entry */ xfs_dir2_leaf_tail_t *ltp; /* leaf tail structure */ int needlog; /* need to log data header */ int needscan; /* need to rescan data frees */ xfs_dir2_data_off_t oldbest; /* old value of best free */ struct xfs_dir2_data_free *bf; /* bestfree table */ struct xfs_dir2_leaf_entry *ents; struct xfs_dir3_icleaf_hdr leafhdr; trace_xfs_dir2_leaf_removename(args); /* * Lookup the leaf entry, get the leaf and data blocks read in. */ if ((error = xfs_dir2_leaf_lookup_int(args, &lbp, &index, &dbp))) { return error; } dp = args->dp; leaf = lbp->b_addr; hdr = dbp->b_addr; xfs_dir3_data_check(dp, dbp); bf = dp->d_ops->data_bestfree_p(hdr); dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf); ents = dp->d_ops->leaf_ents_p(leaf); /* * Point to the leaf entry, use that to point to the data entry. */ lep = &ents[index]; db = xfs_dir2_dataptr_to_db(args->geo, be32_to_cpu(lep->address)); dep = (xfs_dir2_data_entry_t *)((char *)hdr + xfs_dir2_dataptr_to_off(args->geo, be32_to_cpu(lep->address))); needscan = needlog = 0; oldbest = be16_to_cpu(bf[0].length); ltp = xfs_dir2_leaf_tail_p(args->geo, leaf); bestsp = xfs_dir2_leaf_bests_p(ltp); ASSERT(be16_to_cpu(bestsp[db]) == oldbest); /* * Mark the former data entry unused. */ xfs_dir2_data_make_free(args, dbp, (xfs_dir2_data_aoff_t)((char *)dep - (char *)hdr), dp->d_ops->data_entsize(dep->namelen), &needlog, &needscan); /* * We just mark the leaf entry stale by putting a null in it. */ leafhdr.stale++; dp->d_ops->leaf_hdr_to_disk(leaf, &leafhdr); xfs_dir3_leaf_log_header(args, lbp); lep->address = cpu_to_be32(XFS_DIR2_NULL_DATAPTR); xfs_dir3_leaf_log_ents(args, lbp, index, index); /* * Scan the freespace in the data block again if necessary, * log the data block header if necessary. */ if (needscan) xfs_dir2_data_freescan(dp, hdr, &needlog); if (needlog) xfs_dir2_data_log_header(args, dbp); /* * If the longest freespace in the data block has changed, * put the new value in the bests table and log that. */ if (be16_to_cpu(bf[0].length) != oldbest) { bestsp[db] = bf[0].length; xfs_dir3_leaf_log_bests(args, lbp, db, db); } xfs_dir3_data_check(dp, dbp); /* * If the data block is now empty then get rid of the data block. */ if (be16_to_cpu(bf[0].length) == args->geo->blksize - dp->d_ops->data_entry_offset) { ASSERT(db != args->geo->datablk); if ((error = xfs_dir2_shrink_inode(args, db, dbp))) { /* * Nope, can't get rid of it because it caused * allocation of a bmap btree block to do so. * Just go on, returning success, leaving the * empty block in place. */ if (error == -ENOSPC && args->total == 0) error = 0; xfs_dir3_leaf_check(dp, lbp); return error; } dbp = NULL; /* * If this is the last data block then compact the * bests table by getting rid of entries. */ if (db == be32_to_cpu(ltp->bestcount) - 1) { /* * Look for the last active entry (i). */ for (i = db - 1; i > 0; i--) { if (bestsp[i] != cpu_to_be16(NULLDATAOFF)) break; } /* * Copy the table down so inactive entries at the * end are removed. */ memmove(&bestsp[db - i], bestsp, (be32_to_cpu(ltp->bestcount) - (db - i)) * sizeof(*bestsp)); be32_add_cpu(<p->bestcount, -(db - i)); xfs_dir3_leaf_log_tail(args, lbp); xfs_dir3_leaf_log_bests(args, lbp, 0, be32_to_cpu(ltp->bestcount) - 1); } else bestsp[db] = cpu_to_be16(NULLDATAOFF); } /* * If the data block was not the first one, drop it. */ else if (db != args->geo->datablk) dbp = NULL; xfs_dir3_leaf_check(dp, lbp); /* * See if we can convert to block form. */ return xfs_dir2_leaf_to_block(args, lbp, dbp); } /* * Replace the inode number in a leaf format directory entry. */ int /* error */ xfs_dir2_leaf_replace( xfs_da_args_t *args) /* operation arguments */ { struct xfs_buf *dbp; /* data block buffer */ xfs_dir2_data_entry_t *dep; /* data block entry */ xfs_inode_t *dp; /* incore directory inode */ int error; /* error return code */ int index; /* index of leaf entry */ struct xfs_buf *lbp; /* leaf buffer */ xfs_dir2_leaf_t *leaf; /* leaf structure */ xfs_dir2_leaf_entry_t *lep; /* leaf entry */ xfs_trans_t *tp; /* transaction pointer */ struct xfs_dir2_leaf_entry *ents; trace_xfs_dir2_leaf_replace(args); /* * Look up the entry. */ if ((error = xfs_dir2_leaf_lookup_int(args, &lbp, &index, &dbp))) { return error; } dp = args->dp; leaf = lbp->b_addr; ents = dp->d_ops->leaf_ents_p(leaf); /* * Point to the leaf entry, get data address from it. */ lep = &ents[index]; /* * Point to the data entry. */ dep = (xfs_dir2_data_entry_t *) ((char *)dbp->b_addr + xfs_dir2_dataptr_to_off(args->geo, be32_to_cpu(lep->address))); ASSERT(args->inumber != be64_to_cpu(dep->inumber)); /* * Put the new inode number in, log it. */ dep->inumber = cpu_to_be64(args->inumber); dp->d_ops->data_put_ftype(dep, args->filetype); tp = args->trans; xfs_dir2_data_log_entry(args, dbp, dep); xfs_dir3_leaf_check(dp, lbp); xfs_trans_brelse(tp, lbp); return 0; } /* * Return index in the leaf block (lbp) which is either the first * one with this hash value, or if there are none, the insert point * for that hash value. */ int /* index value */ xfs_dir2_leaf_search_hash( xfs_da_args_t *args, /* operation arguments */ struct xfs_buf *lbp) /* leaf buffer */ { xfs_dahash_t hash=0; /* hash from this entry */ xfs_dahash_t hashwant; /* hash value looking for */ int high; /* high leaf index */ int low; /* low leaf index */ xfs_dir2_leaf_t *leaf; /* leaf structure */ xfs_dir2_leaf_entry_t *lep; /* leaf entry */ int mid=0; /* current leaf index */ struct xfs_dir2_leaf_entry *ents; struct xfs_dir3_icleaf_hdr leafhdr; leaf = lbp->b_addr; ents = args->dp->d_ops->leaf_ents_p(leaf); args->dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf); /* * Note, the table cannot be empty, so we have to go through the loop. * Binary search the leaf entries looking for our hash value. */ for (lep = ents, low = 0, high = leafhdr.count - 1, hashwant = args->hashval; low <= high; ) { mid = (low + high) >> 1; if ((hash = be32_to_cpu(lep[mid].hashval)) == hashwant) break; if (hash < hashwant) low = mid + 1; else high = mid - 1; } /* * Found one, back up through all the equal hash values. */ if (hash == hashwant) { while (mid > 0 && be32_to_cpu(lep[mid - 1].hashval) == hashwant) { mid--; } } /* * Need to point to an entry higher than ours. */ else if (hash < hashwant) mid++; return mid; } /* * Trim off a trailing data block. We know it's empty since the leaf * freespace table says so. */ int /* error */ xfs_dir2_leaf_trim_data( xfs_da_args_t *args, /* operation arguments */ struct xfs_buf *lbp, /* leaf buffer */ xfs_dir2_db_t db) /* data block number */ { __be16 *bestsp; /* leaf bests table */ struct xfs_buf *dbp; /* data block buffer */ xfs_inode_t *dp; /* incore directory inode */ int error; /* error return value */ xfs_dir2_leaf_t *leaf; /* leaf structure */ xfs_dir2_leaf_tail_t *ltp; /* leaf tail structure */ xfs_trans_t *tp; /* transaction pointer */ dp = args->dp; tp = args->trans; /* * Read the offending data block. We need its buffer. */ error = xfs_dir3_data_read(tp, dp, xfs_dir2_db_to_da(args->geo, db), -1, &dbp); if (error) return error; leaf = lbp->b_addr; ltp = xfs_dir2_leaf_tail_p(args->geo, leaf); #ifdef DEBUG { struct xfs_dir2_data_hdr *hdr = dbp->b_addr; struct xfs_dir2_data_free *bf = dp->d_ops->data_bestfree_p(hdr); ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC)); ASSERT(be16_to_cpu(bf[0].length) == args->geo->blksize - dp->d_ops->data_entry_offset); ASSERT(db == be32_to_cpu(ltp->bestcount) - 1); } #endif /* * Get rid of the data block. */ if ((error = xfs_dir2_shrink_inode(args, db, dbp))) { ASSERT(error != -ENOSPC); xfs_trans_brelse(tp, dbp); return error; } /* * Eliminate the last bests entry from the table. */ bestsp = xfs_dir2_leaf_bests_p(ltp); be32_add_cpu(<p->bestcount, -1); memmove(&bestsp[1], &bestsp[0], be32_to_cpu(ltp->bestcount) * sizeof(*bestsp)); xfs_dir3_leaf_log_tail(args, lbp); xfs_dir3_leaf_log_bests(args, lbp, 0, be32_to_cpu(ltp->bestcount) - 1); return 0; } static inline size_t xfs_dir3_leaf_size( struct xfs_dir3_icleaf_hdr *hdr, int counts) { int entries; int hdrsize; entries = hdr->count - hdr->stale; if (hdr->magic == XFS_DIR2_LEAF1_MAGIC || hdr->magic == XFS_DIR2_LEAFN_MAGIC) hdrsize = sizeof(struct xfs_dir2_leaf_hdr); else hdrsize = sizeof(struct xfs_dir3_leaf_hdr); return hdrsize + entries * sizeof(xfs_dir2_leaf_entry_t) + counts * sizeof(xfs_dir2_data_off_t) + sizeof(xfs_dir2_leaf_tail_t); } /* * Convert node form directory to leaf form directory. * The root of the node form dir needs to already be a LEAFN block. * Just return if we can't do anything. */ int /* error */ xfs_dir2_node_to_leaf( xfs_da_state_t *state) /* directory operation state */ { xfs_da_args_t *args; /* operation arguments */ xfs_inode_t *dp; /* incore directory inode */ int error; /* error return code */ struct xfs_buf *fbp; /* buffer for freespace block */ xfs_fileoff_t fo; /* freespace file offset */ xfs_dir2_free_t *free; /* freespace structure */ struct xfs_buf *lbp; /* buffer for leaf block */ xfs_dir2_leaf_tail_t *ltp; /* tail of leaf structure */ xfs_dir2_leaf_t *leaf; /* leaf structure */ xfs_mount_t *mp; /* filesystem mount point */ int rval; /* successful free trim? */ xfs_trans_t *tp; /* transaction pointer */ struct xfs_dir3_icleaf_hdr leafhdr; struct xfs_dir3_icfree_hdr freehdr; /* * There's more than a leaf level in the btree, so there must * be multiple leafn blocks. Give up. */ if (state->path.active > 1) return 0; args = state->args; trace_xfs_dir2_node_to_leaf(args); mp = state->mp; dp = args->dp; tp = args->trans; /* * Get the last offset in the file. */ if ((error = xfs_bmap_last_offset(dp, &fo, XFS_DATA_FORK))) { return error; } fo -= args->geo->fsbcount; /* * If there are freespace blocks other than the first one, * take this opportunity to remove trailing empty freespace blocks * that may have been left behind during no-space-reservation * operations. */ while (fo > args->geo->freeblk) { if ((error = xfs_dir2_node_trim_free(args, fo, &rval))) { return error; } if (rval) fo -= args->geo->fsbcount; else return 0; } /* * Now find the block just before the freespace block. */ if ((error = xfs_bmap_last_before(tp, dp, &fo, XFS_DATA_FORK))) { return error; } /* * If it's not the single leaf block, give up. */ if (XFS_FSB_TO_B(mp, fo) > XFS_DIR2_LEAF_OFFSET + args->geo->blksize) return 0; lbp = state->path.blk[0].bp; leaf = lbp->b_addr; dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf); ASSERT(leafhdr.magic == XFS_DIR2_LEAFN_MAGIC || leafhdr.magic == XFS_DIR3_LEAFN_MAGIC); /* * Read the freespace block. */ error = xfs_dir2_free_read(tp, dp, args->geo->freeblk, &fbp); if (error) return error; free = fbp->b_addr; dp->d_ops->free_hdr_from_disk(&freehdr, free); ASSERT(!freehdr.firstdb); /* * Now see if the leafn and free data will fit in a leaf1. * If not, release the buffer and give up. */ if (xfs_dir3_leaf_size(&leafhdr, freehdr.nvalid) > args->geo->blksize) { xfs_trans_brelse(tp, fbp); return 0; } /* * If the leaf has any stale entries in it, compress them out. */ if (leafhdr.stale) xfs_dir3_leaf_compact(args, &leafhdr, lbp); lbp->b_ops = &xfs_dir3_leaf1_buf_ops; xfs_trans_buf_set_type(tp, lbp, XFS_BLFT_DIR_LEAF1_BUF); leafhdr.magic = (leafhdr.magic == XFS_DIR2_LEAFN_MAGIC) ? XFS_DIR2_LEAF1_MAGIC : XFS_DIR3_LEAF1_MAGIC; /* * Set up the leaf tail from the freespace block. */ ltp = xfs_dir2_leaf_tail_p(args->geo, leaf); ltp->bestcount = cpu_to_be32(freehdr.nvalid); /* * Set up the leaf bests table. */ memcpy(xfs_dir2_leaf_bests_p(ltp), dp->d_ops->free_bests_p(free), freehdr.nvalid * sizeof(xfs_dir2_data_off_t)); dp->d_ops->leaf_hdr_to_disk(leaf, &leafhdr); xfs_dir3_leaf_log_header(args, lbp); xfs_dir3_leaf_log_bests(args, lbp, 0, be32_to_cpu(ltp->bestcount) - 1); xfs_dir3_leaf_log_tail(args, lbp); xfs_dir3_leaf_check(dp, lbp); /* * Get rid of the freespace block. */ error = xfs_dir2_shrink_inode(args, xfs_dir2_byte_to_db(args->geo, XFS_DIR2_FREE_OFFSET), fbp); if (error) { /* * This can't fail here because it can only happen when * punching out the middle of an extent, and this is an * isolated block. */ ASSERT(error != -ENOSPC); return error; } fbp = NULL; /* * Now see if we can convert the single-leaf directory * down to a block form directory. * This routine always kills the dabuf for the leaf, so * eliminate it from the path. */ error = xfs_dir2_leaf_to_block(args, lbp, NULL); state->path.blk[0].bp = NULL; return error; } partclone-0.2.86/src/xfs/xfs_dir2_node.c000066400000000000000000001734371262102574200200760ustar00rootroot00000000000000/* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * Copyright (c) 2013 Red Hat, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_mount.h" #include "xfs_da_format.h" #include "xfs_da_btree.h" #include "xfs_inode.h" #include "xfs_bmap.h" #include "xfs_dir2.h" #include "xfs_dir2_priv.h" #include "xfs_trace.h" #include "xfs_trans.h" #include "xfs_cksum.h" /* * Function declarations. */ static int xfs_dir2_leafn_add(struct xfs_buf *bp, xfs_da_args_t *args, int index); static void xfs_dir2_leafn_rebalance(xfs_da_state_t *state, xfs_da_state_blk_t *blk1, xfs_da_state_blk_t *blk2); static int xfs_dir2_leafn_remove(xfs_da_args_t *args, struct xfs_buf *bp, int index, xfs_da_state_blk_t *dblk, int *rval); static int xfs_dir2_node_addname_int(xfs_da_args_t *args, xfs_da_state_blk_t *fblk); /* * Check internal consistency of a leafn block. */ #ifdef DEBUG #define xfs_dir3_leaf_check(dp, bp) \ do { \ if (!xfs_dir3_leafn_check((dp), (bp))) \ ASSERT(0); \ } while (0); static bool xfs_dir3_leafn_check( struct xfs_inode *dp, struct xfs_buf *bp) { struct xfs_dir2_leaf *leaf = bp->b_addr; struct xfs_dir3_icleaf_hdr leafhdr; dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf); if (leafhdr.magic == XFS_DIR3_LEAFN_MAGIC) { struct xfs_dir3_leaf_hdr *leaf3 = bp->b_addr; if (be64_to_cpu(leaf3->info.blkno) != bp->b_bn) return false; } else if (leafhdr.magic != XFS_DIR2_LEAFN_MAGIC) return false; return xfs_dir3_leaf_check_int(dp->i_mount, dp, &leafhdr, leaf); } #else #define xfs_dir3_leaf_check(dp, bp) #endif static bool xfs_dir3_free_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_target->bt_mount; struct xfs_dir2_free_hdr *hdr = bp->b_addr; if (xfs_sb_version_hascrc(&mp->m_sb)) { struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr; if (hdr3->magic != cpu_to_be32(XFS_DIR3_FREE_MAGIC)) return false; if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_meta_uuid)) return false; if (be64_to_cpu(hdr3->blkno) != bp->b_bn) return false; } else { if (hdr->magic != cpu_to_be32(XFS_DIR2_FREE_MAGIC)) return false; } /* XXX: should bounds check the xfs_dir3_icfree_hdr here */ return true; } static void xfs_dir3_free_read_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_target->bt_mount; if (xfs_sb_version_hascrc(&mp->m_sb) && !xfs_buf_verify_cksum(bp, XFS_DIR3_FREE_CRC_OFF)) xfs_buf_ioerror(bp, -EFSBADCRC); else if (!xfs_dir3_free_verify(bp)) xfs_buf_ioerror(bp, -EFSCORRUPTED); if (bp->b_error) xfs_verifier_error(bp); } static void xfs_dir3_free_write_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_target->bt_mount; struct xfs_buf_log_item *bip = bp->b_fspriv; struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr; if (!xfs_dir3_free_verify(bp)) { xfs_buf_ioerror(bp, -EFSCORRUPTED); xfs_verifier_error(bp); return; } if (!xfs_sb_version_hascrc(&mp->m_sb)) return; if (bip) hdr3->lsn = cpu_to_be64(bip->bli_item.li_lsn); xfs_buf_update_cksum(bp, XFS_DIR3_FREE_CRC_OFF); } const struct xfs_buf_ops xfs_dir3_free_buf_ops = { .verify_read = xfs_dir3_free_read_verify, .verify_write = xfs_dir3_free_write_verify, }; static int __xfs_dir3_free_read( struct xfs_trans *tp, struct xfs_inode *dp, xfs_dablk_t fbno, xfs_daddr_t mappedbno, struct xfs_buf **bpp) { int err; err = xfs_da_read_buf(tp, dp, fbno, mappedbno, bpp, XFS_DATA_FORK, &xfs_dir3_free_buf_ops); /* try read returns without an error or *bpp if it lands in a hole */ if (!err && tp && *bpp) xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_DIR_FREE_BUF); return err; } int xfs_dir2_free_read( struct xfs_trans *tp, struct xfs_inode *dp, xfs_dablk_t fbno, struct xfs_buf **bpp) { return __xfs_dir3_free_read(tp, dp, fbno, -1, bpp); } static int xfs_dir2_free_try_read( struct xfs_trans *tp, struct xfs_inode *dp, xfs_dablk_t fbno, struct xfs_buf **bpp) { return __xfs_dir3_free_read(tp, dp, fbno, -2, bpp); } static int xfs_dir3_free_get_buf( xfs_da_args_t *args, xfs_dir2_db_t fbno, struct xfs_buf **bpp) { struct xfs_trans *tp = args->trans; struct xfs_inode *dp = args->dp; struct xfs_mount *mp = dp->i_mount; struct xfs_buf *bp; int error; struct xfs_dir3_icfree_hdr hdr; error = xfs_da_get_buf(tp, dp, xfs_dir2_db_to_da(args->geo, fbno), -1, &bp, XFS_DATA_FORK); if (error) return error; xfs_trans_buf_set_type(tp, bp, XFS_BLFT_DIR_FREE_BUF); bp->b_ops = &xfs_dir3_free_buf_ops; /* * Initialize the new block to be empty, and remember * its first slot as our empty slot. */ memset(bp->b_addr, 0, sizeof(struct xfs_dir3_free_hdr)); memset(&hdr, 0, sizeof(hdr)); if (xfs_sb_version_hascrc(&mp->m_sb)) { struct xfs_dir3_free_hdr *hdr3 = bp->b_addr; hdr.magic = XFS_DIR3_FREE_MAGIC; hdr3->hdr.blkno = cpu_to_be64(bp->b_bn); hdr3->hdr.owner = cpu_to_be64(dp->i_ino); uuid_copy(&hdr3->hdr.uuid, &mp->m_sb.sb_meta_uuid); } else hdr.magic = XFS_DIR2_FREE_MAGIC; dp->d_ops->free_hdr_to_disk(bp->b_addr, &hdr); *bpp = bp; return 0; } /* * Log entries from a freespace block. */ STATIC void xfs_dir2_free_log_bests( struct xfs_da_args *args, struct xfs_buf *bp, int first, /* first entry to log */ int last) /* last entry to log */ { xfs_dir2_free_t *free; /* freespace structure */ __be16 *bests; free = bp->b_addr; bests = args->dp->d_ops->free_bests_p(free); ASSERT(free->hdr.magic == cpu_to_be32(XFS_DIR2_FREE_MAGIC) || free->hdr.magic == cpu_to_be32(XFS_DIR3_FREE_MAGIC)); xfs_trans_log_buf(args->trans, bp, (uint)((char *)&bests[first] - (char *)free), (uint)((char *)&bests[last] - (char *)free + sizeof(bests[0]) - 1)); } /* * Log header from a freespace block. */ static void xfs_dir2_free_log_header( struct xfs_da_args *args, struct xfs_buf *bp) { #ifdef DEBUG xfs_dir2_free_t *free; /* freespace structure */ free = bp->b_addr; ASSERT(free->hdr.magic == cpu_to_be32(XFS_DIR2_FREE_MAGIC) || free->hdr.magic == cpu_to_be32(XFS_DIR3_FREE_MAGIC)); #endif xfs_trans_log_buf(args->trans, bp, 0, args->dp->d_ops->free_hdr_size - 1); } /* * Convert a leaf-format directory to a node-format directory. * We need to change the magic number of the leaf block, and copy * the freespace table out of the leaf block into its own block. */ int /* error */ xfs_dir2_leaf_to_node( xfs_da_args_t *args, /* operation arguments */ struct xfs_buf *lbp) /* leaf buffer */ { xfs_inode_t *dp; /* incore directory inode */ int error; /* error return value */ struct xfs_buf *fbp; /* freespace buffer */ xfs_dir2_db_t fdb; /* freespace block number */ xfs_dir2_free_t *free; /* freespace structure */ __be16 *from; /* pointer to freespace entry */ int i; /* leaf freespace index */ xfs_dir2_leaf_t *leaf; /* leaf structure */ xfs_dir2_leaf_tail_t *ltp; /* leaf tail structure */ int n; /* count of live freespc ents */ xfs_dir2_data_off_t off; /* freespace entry value */ __be16 *to; /* pointer to freespace entry */ xfs_trans_t *tp; /* transaction pointer */ struct xfs_dir3_icfree_hdr freehdr; trace_xfs_dir2_leaf_to_node(args); dp = args->dp; tp = args->trans; /* * Add a freespace block to the directory. */ if ((error = xfs_dir2_grow_inode(args, XFS_DIR2_FREE_SPACE, &fdb))) { return error; } ASSERT(fdb == xfs_dir2_byte_to_db(args->geo, XFS_DIR2_FREE_OFFSET)); /* * Get the buffer for the new freespace block. */ error = xfs_dir3_free_get_buf(args, fdb, &fbp); if (error) return error; free = fbp->b_addr; dp->d_ops->free_hdr_from_disk(&freehdr, free); leaf = lbp->b_addr; ltp = xfs_dir2_leaf_tail_p(args->geo, leaf); ASSERT(be32_to_cpu(ltp->bestcount) <= (uint)dp->i_d.di_size / args->geo->blksize); /* * Copy freespace entries from the leaf block to the new block. * Count active entries. */ from = xfs_dir2_leaf_bests_p(ltp); to = dp->d_ops->free_bests_p(free); for (i = n = 0; i < be32_to_cpu(ltp->bestcount); i++, from++, to++) { if ((off = be16_to_cpu(*from)) != NULLDATAOFF) n++; *to = cpu_to_be16(off); } /* * Now initialize the freespace block header. */ freehdr.nused = n; freehdr.nvalid = be32_to_cpu(ltp->bestcount); dp->d_ops->free_hdr_to_disk(fbp->b_addr, &freehdr); xfs_dir2_free_log_bests(args, fbp, 0, freehdr.nvalid - 1); xfs_dir2_free_log_header(args, fbp); /* * Converting the leaf to a leafnode is just a matter of changing the * magic number and the ops. Do the change directly to the buffer as * it's less work (and less code) than decoding the header to host * format and back again. */ if (leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAF1_MAGIC)) leaf->hdr.info.magic = cpu_to_be16(XFS_DIR2_LEAFN_MAGIC); else leaf->hdr.info.magic = cpu_to_be16(XFS_DIR3_LEAFN_MAGIC); lbp->b_ops = &xfs_dir3_leafn_buf_ops; xfs_trans_buf_set_type(tp, lbp, XFS_BLFT_DIR_LEAFN_BUF); xfs_dir3_leaf_log_header(args, lbp); xfs_dir3_leaf_check(dp, lbp); return 0; } /* * Add a leaf entry to a leaf block in a node-form directory. * The other work necessary is done from the caller. */ static int /* error */ xfs_dir2_leafn_add( struct xfs_buf *bp, /* leaf buffer */ xfs_da_args_t *args, /* operation arguments */ int index) /* insertion pt for new entry */ { int compact; /* compacting stale leaves */ xfs_inode_t *dp; /* incore directory inode */ int highstale; /* next stale entry */ xfs_dir2_leaf_t *leaf; /* leaf structure */ xfs_dir2_leaf_entry_t *lep; /* leaf entry */ int lfloghigh; /* high leaf entry logging */ int lfloglow; /* low leaf entry logging */ int lowstale; /* previous stale entry */ struct xfs_dir3_icleaf_hdr leafhdr; struct xfs_dir2_leaf_entry *ents; trace_xfs_dir2_leafn_add(args, index); dp = args->dp; leaf = bp->b_addr; dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf); ents = dp->d_ops->leaf_ents_p(leaf); /* * Quick check just to make sure we are not going to index * into other peoples memory */ if (index < 0) return -EFSCORRUPTED; /* * If there are already the maximum number of leaf entries in * the block, if there are no stale entries it won't fit. * Caller will do a split. If there are stale entries we'll do * a compact. */ if (leafhdr.count == dp->d_ops->leaf_max_ents(args->geo)) { if (!leafhdr.stale) return -ENOSPC; compact = leafhdr.stale > 1; } else compact = 0; ASSERT(index == 0 || be32_to_cpu(ents[index - 1].hashval) <= args->hashval); ASSERT(index == leafhdr.count || be32_to_cpu(ents[index].hashval) >= args->hashval); if (args->op_flags & XFS_DA_OP_JUSTCHECK) return 0; /* * Compact out all but one stale leaf entry. Leaves behind * the entry closest to index. */ if (compact) xfs_dir3_leaf_compact_x1(&leafhdr, ents, &index, &lowstale, &highstale, &lfloglow, &lfloghigh); else if (leafhdr.stale) { /* * Set impossible logging indices for this case. */ lfloglow = leafhdr.count; lfloghigh = -1; } /* * Insert the new entry, log everything. */ lep = xfs_dir3_leaf_find_entry(&leafhdr, ents, index, compact, lowstale, highstale, &lfloglow, &lfloghigh); lep->hashval = cpu_to_be32(args->hashval); lep->address = cpu_to_be32(xfs_dir2_db_off_to_dataptr(args->geo, args->blkno, args->index)); dp->d_ops->leaf_hdr_to_disk(leaf, &leafhdr); xfs_dir3_leaf_log_header(args, bp); xfs_dir3_leaf_log_ents(args, bp, lfloglow, lfloghigh); xfs_dir3_leaf_check(dp, bp); return 0; } #ifdef DEBUG static void xfs_dir2_free_hdr_check( struct xfs_inode *dp, struct xfs_buf *bp, xfs_dir2_db_t db) { struct xfs_dir3_icfree_hdr hdr; dp->d_ops->free_hdr_from_disk(&hdr, bp->b_addr); ASSERT((hdr.firstdb % dp->d_ops->free_max_bests(dp->i_mount->m_dir_geo)) == 0); ASSERT(hdr.firstdb <= db); ASSERT(db < hdr.firstdb + hdr.nvalid); } #else #define xfs_dir2_free_hdr_check(dp, bp, db) #endif /* DEBUG */ /* * Return the last hash value in the leaf. * Stale entries are ok. */ xfs_dahash_t /* hash value */ xfs_dir2_leafn_lasthash( struct xfs_inode *dp, struct xfs_buf *bp, /* leaf buffer */ int *count) /* count of entries in leaf */ { struct xfs_dir2_leaf *leaf = bp->b_addr; struct xfs_dir2_leaf_entry *ents; struct xfs_dir3_icleaf_hdr leafhdr; dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf); ASSERT(leafhdr.magic == XFS_DIR2_LEAFN_MAGIC || leafhdr.magic == XFS_DIR3_LEAFN_MAGIC); if (count) *count = leafhdr.count; if (!leafhdr.count) return 0; ents = dp->d_ops->leaf_ents_p(leaf); return be32_to_cpu(ents[leafhdr.count - 1].hashval); } /* * Look up a leaf entry for space to add a name in a node-format leaf block. * The extrablk in state is a freespace block. */ STATIC int xfs_dir2_leafn_lookup_for_addname( struct xfs_buf *bp, /* leaf buffer */ xfs_da_args_t *args, /* operation arguments */ int *indexp, /* out: leaf entry index */ xfs_da_state_t *state) /* state to fill in */ { struct xfs_buf *curbp = NULL; /* current data/free buffer */ xfs_dir2_db_t curdb = -1; /* current data block number */ xfs_dir2_db_t curfdb = -1; /* current free block number */ xfs_inode_t *dp; /* incore directory inode */ int error; /* error return value */ int fi; /* free entry index */ xfs_dir2_free_t *free = NULL; /* free block structure */ int index; /* leaf entry index */ xfs_dir2_leaf_t *leaf; /* leaf structure */ int length; /* length of new data entry */ xfs_dir2_leaf_entry_t *lep; /* leaf entry */ xfs_mount_t *mp; /* filesystem mount point */ xfs_dir2_db_t newdb; /* new data block number */ xfs_dir2_db_t newfdb; /* new free block number */ xfs_trans_t *tp; /* transaction pointer */ struct xfs_dir2_leaf_entry *ents; struct xfs_dir3_icleaf_hdr leafhdr; dp = args->dp; tp = args->trans; mp = dp->i_mount; leaf = bp->b_addr; dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf); ents = dp->d_ops->leaf_ents_p(leaf); xfs_dir3_leaf_check(dp, bp); ASSERT(leafhdr.count > 0); /* * Look up the hash value in the leaf entries. */ index = xfs_dir2_leaf_search_hash(args, bp); /* * Do we have a buffer coming in? */ if (state->extravalid) { /* If so, it's a free block buffer, get the block number. */ curbp = state->extrablk.bp; curfdb = state->extrablk.blkno; free = curbp->b_addr; ASSERT(free->hdr.magic == cpu_to_be32(XFS_DIR2_FREE_MAGIC) || free->hdr.magic == cpu_to_be32(XFS_DIR3_FREE_MAGIC)); } length = dp->d_ops->data_entsize(args->namelen); /* * Loop over leaf entries with the right hash value. */ for (lep = &ents[index]; index < leafhdr.count && be32_to_cpu(lep->hashval) == args->hashval; lep++, index++) { /* * Skip stale leaf entries. */ if (be32_to_cpu(lep->address) == XFS_DIR2_NULL_DATAPTR) continue; /* * Pull the data block number from the entry. */ newdb = xfs_dir2_dataptr_to_db(args->geo, be32_to_cpu(lep->address)); /* * For addname, we're looking for a place to put the new entry. * We want to use a data block with an entry of equal * hash value to ours if there is one with room. * * If this block isn't the data block we already have * in hand, take a look at it. */ if (newdb != curdb) { __be16 *bests; curdb = newdb; /* * Convert the data block to the free block * holding its freespace information. */ newfdb = dp->d_ops->db_to_fdb(args->geo, newdb); /* * If it's not the one we have in hand, read it in. */ if (newfdb != curfdb) { /* * If we had one before, drop it. */ if (curbp) xfs_trans_brelse(tp, curbp); error = xfs_dir2_free_read(tp, dp, xfs_dir2_db_to_da(args->geo, newfdb), &curbp); if (error) return error; free = curbp->b_addr; xfs_dir2_free_hdr_check(dp, curbp, curdb); } /* * Get the index for our entry. */ fi = dp->d_ops->db_to_fdindex(args->geo, curdb); /* * If it has room, return it. */ bests = dp->d_ops->free_bests_p(free); if (unlikely(bests[fi] == cpu_to_be16(NULLDATAOFF))) { XFS_ERROR_REPORT("xfs_dir2_leafn_lookup_int", XFS_ERRLEVEL_LOW, mp); if (curfdb != newfdb) xfs_trans_brelse(tp, curbp); return -EFSCORRUPTED; } curfdb = newfdb; if (be16_to_cpu(bests[fi]) >= length) goto out; } } /* Didn't find any space */ fi = -1; out: ASSERT(args->op_flags & XFS_DA_OP_OKNOENT); if (curbp) { /* Giving back a free block. */ state->extravalid = 1; state->extrablk.bp = curbp; state->extrablk.index = fi; state->extrablk.blkno = curfdb; /* * Important: this magic number is not in the buffer - it's for * buffer type information and therefore only the free/data type * matters here, not whether CRCs are enabled or not. */ state->extrablk.magic = XFS_DIR2_FREE_MAGIC; } else { state->extravalid = 0; } /* * Return the index, that will be the insertion point. */ *indexp = index; return -ENOENT; } /* * Look up a leaf entry in a node-format leaf block. * The extrablk in state a data block. */ STATIC int xfs_dir2_leafn_lookup_for_entry( struct xfs_buf *bp, /* leaf buffer */ xfs_da_args_t *args, /* operation arguments */ int *indexp, /* out: leaf entry index */ xfs_da_state_t *state) /* state to fill in */ { struct xfs_buf *curbp = NULL; /* current data/free buffer */ xfs_dir2_db_t curdb = -1; /* current data block number */ xfs_dir2_data_entry_t *dep; /* data block entry */ xfs_inode_t *dp; /* incore directory inode */ int error; /* error return value */ int index; /* leaf entry index */ xfs_dir2_leaf_t *leaf; /* leaf structure */ xfs_dir2_leaf_entry_t *lep; /* leaf entry */ xfs_mount_t *mp; /* filesystem mount point */ xfs_dir2_db_t newdb; /* new data block number */ xfs_trans_t *tp; /* transaction pointer */ enum xfs_dacmp cmp; /* comparison result */ struct xfs_dir2_leaf_entry *ents; struct xfs_dir3_icleaf_hdr leafhdr; dp = args->dp; tp = args->trans; mp = dp->i_mount; leaf = bp->b_addr; dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf); ents = dp->d_ops->leaf_ents_p(leaf); xfs_dir3_leaf_check(dp, bp); ASSERT(leafhdr.count > 0); /* * Look up the hash value in the leaf entries. */ index = xfs_dir2_leaf_search_hash(args, bp); /* * Do we have a buffer coming in? */ if (state->extravalid) { curbp = state->extrablk.bp; curdb = state->extrablk.blkno; } /* * Loop over leaf entries with the right hash value. */ for (lep = &ents[index]; index < leafhdr.count && be32_to_cpu(lep->hashval) == args->hashval; lep++, index++) { /* * Skip stale leaf entries. */ if (be32_to_cpu(lep->address) == XFS_DIR2_NULL_DATAPTR) continue; /* * Pull the data block number from the entry. */ newdb = xfs_dir2_dataptr_to_db(args->geo, be32_to_cpu(lep->address)); /* * Not adding a new entry, so we really want to find * the name given to us. * * If it's a different data block, go get it. */ if (newdb != curdb) { /* * If we had a block before that we aren't saving * for a CI name, drop it */ if (curbp && (args->cmpresult == XFS_CMP_DIFFERENT || curdb != state->extrablk.blkno)) xfs_trans_brelse(tp, curbp); /* * If needing the block that is saved with a CI match, * use it otherwise read in the new data block. */ if (args->cmpresult != XFS_CMP_DIFFERENT && newdb == state->extrablk.blkno) { ASSERT(state->extravalid); curbp = state->extrablk.bp; } else { error = xfs_dir3_data_read(tp, dp, xfs_dir2_db_to_da(args->geo, newdb), -1, &curbp); if (error) return error; } xfs_dir3_data_check(dp, curbp); curdb = newdb; } /* * Point to the data entry. */ dep = (xfs_dir2_data_entry_t *)((char *)curbp->b_addr + xfs_dir2_dataptr_to_off(args->geo, be32_to_cpu(lep->address))); /* * Compare the entry and if it's an exact match, return * EEXIST immediately. If it's the first case-insensitive * match, store the block & inode number and continue looking. */ cmp = mp->m_dirnameops->compname(args, dep->name, dep->namelen); if (cmp != XFS_CMP_DIFFERENT && cmp != args->cmpresult) { /* If there is a CI match block, drop it */ if (args->cmpresult != XFS_CMP_DIFFERENT && curdb != state->extrablk.blkno) xfs_trans_brelse(tp, state->extrablk.bp); args->cmpresult = cmp; args->inumber = be64_to_cpu(dep->inumber); args->filetype = dp->d_ops->data_get_ftype(dep); *indexp = index; state->extravalid = 1; state->extrablk.bp = curbp; state->extrablk.blkno = curdb; state->extrablk.index = (int)((char *)dep - (char *)curbp->b_addr); state->extrablk.magic = XFS_DIR2_DATA_MAGIC; curbp->b_ops = &xfs_dir3_data_buf_ops; xfs_trans_buf_set_type(tp, curbp, XFS_BLFT_DIR_DATA_BUF); if (cmp == XFS_CMP_EXACT) return -EEXIST; } } ASSERT(index == leafhdr.count || (args->op_flags & XFS_DA_OP_OKNOENT)); if (curbp) { if (args->cmpresult == XFS_CMP_DIFFERENT) { /* Giving back last used data block. */ state->extravalid = 1; state->extrablk.bp = curbp; state->extrablk.index = -1; state->extrablk.blkno = curdb; state->extrablk.magic = XFS_DIR2_DATA_MAGIC; curbp->b_ops = &xfs_dir3_data_buf_ops; xfs_trans_buf_set_type(tp, curbp, XFS_BLFT_DIR_DATA_BUF); } else { /* If the curbp is not the CI match block, drop it */ if (state->extrablk.bp != curbp) xfs_trans_brelse(tp, curbp); } } else { state->extravalid = 0; } *indexp = index; return -ENOENT; } /* * Look up a leaf entry in a node-format leaf block. * If this is an addname then the extrablk in state is a freespace block, * otherwise it's a data block. */ int xfs_dir2_leafn_lookup_int( struct xfs_buf *bp, /* leaf buffer */ xfs_da_args_t *args, /* operation arguments */ int *indexp, /* out: leaf entry index */ xfs_da_state_t *state) /* state to fill in */ { if (args->op_flags & XFS_DA_OP_ADDNAME) return xfs_dir2_leafn_lookup_for_addname(bp, args, indexp, state); return xfs_dir2_leafn_lookup_for_entry(bp, args, indexp, state); } /* * Move count leaf entries from source to destination leaf. * Log entries and headers. Stale entries are preserved. */ static void xfs_dir3_leafn_moveents( xfs_da_args_t *args, /* operation arguments */ struct xfs_buf *bp_s, /* source */ struct xfs_dir3_icleaf_hdr *shdr, struct xfs_dir2_leaf_entry *sents, int start_s,/* source leaf index */ struct xfs_buf *bp_d, /* destination */ struct xfs_dir3_icleaf_hdr *dhdr, struct xfs_dir2_leaf_entry *dents, int start_d,/* destination leaf index */ int count) /* count of leaves to copy */ { int stale; /* count stale leaves copied */ trace_xfs_dir2_leafn_moveents(args, start_s, start_d, count); /* * Silently return if nothing to do. */ if (count == 0) return; /* * If the destination index is not the end of the current * destination leaf entries, open up a hole in the destination * to hold the new entries. */ if (start_d < dhdr->count) { memmove(&dents[start_d + count], &dents[start_d], (dhdr->count - start_d) * sizeof(xfs_dir2_leaf_entry_t)); xfs_dir3_leaf_log_ents(args, bp_d, start_d + count, count + dhdr->count - 1); } /* * If the source has stale leaves, count the ones in the copy range * so we can update the header correctly. */ if (shdr->stale) { int i; /* temp leaf index */ for (i = start_s, stale = 0; i < start_s + count; i++) { if (sents[i].address == cpu_to_be32(XFS_DIR2_NULL_DATAPTR)) stale++; } } else stale = 0; /* * Copy the leaf entries from source to destination. */ memcpy(&dents[start_d], &sents[start_s], count * sizeof(xfs_dir2_leaf_entry_t)); xfs_dir3_leaf_log_ents(args, bp_d, start_d, start_d + count - 1); /* * If there are source entries after the ones we copied, * delete the ones we copied by sliding the next ones down. */ if (start_s + count < shdr->count) { memmove(&sents[start_s], &sents[start_s + count], count * sizeof(xfs_dir2_leaf_entry_t)); xfs_dir3_leaf_log_ents(args, bp_s, start_s, start_s + count - 1); } /* * Update the headers and log them. */ shdr->count -= count; shdr->stale -= stale; dhdr->count += count; dhdr->stale += stale; } /* * Determine the sort order of two leaf blocks. * Returns 1 if both are valid and leaf2 should be before leaf1, else 0. */ int /* sort order */ xfs_dir2_leafn_order( struct xfs_inode *dp, struct xfs_buf *leaf1_bp, /* leaf1 buffer */ struct xfs_buf *leaf2_bp) /* leaf2 buffer */ { struct xfs_dir2_leaf *leaf1 = leaf1_bp->b_addr; struct xfs_dir2_leaf *leaf2 = leaf2_bp->b_addr; struct xfs_dir2_leaf_entry *ents1; struct xfs_dir2_leaf_entry *ents2; struct xfs_dir3_icleaf_hdr hdr1; struct xfs_dir3_icleaf_hdr hdr2; dp->d_ops->leaf_hdr_from_disk(&hdr1, leaf1); dp->d_ops->leaf_hdr_from_disk(&hdr2, leaf2); ents1 = dp->d_ops->leaf_ents_p(leaf1); ents2 = dp->d_ops->leaf_ents_p(leaf2); if (hdr1.count > 0 && hdr2.count > 0 && (be32_to_cpu(ents2[0].hashval) < be32_to_cpu(ents1[0].hashval) || be32_to_cpu(ents2[hdr2.count - 1].hashval) < be32_to_cpu(ents1[hdr1.count - 1].hashval))) return 1; return 0; } /* * Rebalance leaf entries between two leaf blocks. * This is actually only called when the second block is new, * though the code deals with the general case. * A new entry will be inserted in one of the blocks, and that * entry is taken into account when balancing. */ static void xfs_dir2_leafn_rebalance( xfs_da_state_t *state, /* btree cursor */ xfs_da_state_blk_t *blk1, /* first btree block */ xfs_da_state_blk_t *blk2) /* second btree block */ { xfs_da_args_t *args; /* operation arguments */ int count; /* count (& direction) leaves */ int isleft; /* new goes in left leaf */ xfs_dir2_leaf_t *leaf1; /* first leaf structure */ xfs_dir2_leaf_t *leaf2; /* second leaf structure */ int mid; /* midpoint leaf index */ #if defined(DEBUG) || defined(XFS_WARN) int oldstale; /* old count of stale leaves */ #endif int oldsum; /* old total leaf count */ int swap; /* swapped leaf blocks */ struct xfs_dir2_leaf_entry *ents1; struct xfs_dir2_leaf_entry *ents2; struct xfs_dir3_icleaf_hdr hdr1; struct xfs_dir3_icleaf_hdr hdr2; struct xfs_inode *dp = state->args->dp; args = state->args; /* * If the block order is wrong, swap the arguments. */ if ((swap = xfs_dir2_leafn_order(dp, blk1->bp, blk2->bp))) { xfs_da_state_blk_t *tmp; /* temp for block swap */ tmp = blk1; blk1 = blk2; blk2 = tmp; } leaf1 = blk1->bp->b_addr; leaf2 = blk2->bp->b_addr; dp->d_ops->leaf_hdr_from_disk(&hdr1, leaf1); dp->d_ops->leaf_hdr_from_disk(&hdr2, leaf2); ents1 = dp->d_ops->leaf_ents_p(leaf1); ents2 = dp->d_ops->leaf_ents_p(leaf2); oldsum = hdr1.count + hdr2.count; #if defined(DEBUG) || defined(XFS_WARN) oldstale = hdr1.stale + hdr2.stale; #endif mid = oldsum >> 1; /* * If the old leaf count was odd then the new one will be even, * so we need to divide the new count evenly. */ if (oldsum & 1) { xfs_dahash_t midhash; /* middle entry hash value */ if (mid >= hdr1.count) midhash = be32_to_cpu(ents2[mid - hdr1.count].hashval); else midhash = be32_to_cpu(ents1[mid].hashval); isleft = args->hashval <= midhash; } /* * If the old count is even then the new count is odd, so there's * no preferred side for the new entry. * Pick the left one. */ else isleft = 1; /* * Calculate moved entry count. Positive means left-to-right, * negative means right-to-left. Then move the entries. */ count = hdr1.count - mid + (isleft == 0); if (count > 0) xfs_dir3_leafn_moveents(args, blk1->bp, &hdr1, ents1, hdr1.count - count, blk2->bp, &hdr2, ents2, 0, count); else if (count < 0) xfs_dir3_leafn_moveents(args, blk2->bp, &hdr2, ents2, 0, blk1->bp, &hdr1, ents1, hdr1.count, count); ASSERT(hdr1.count + hdr2.count == oldsum); ASSERT(hdr1.stale + hdr2.stale == oldstale); /* log the changes made when moving the entries */ dp->d_ops->leaf_hdr_to_disk(leaf1, &hdr1); dp->d_ops->leaf_hdr_to_disk(leaf2, &hdr2); xfs_dir3_leaf_log_header(args, blk1->bp); xfs_dir3_leaf_log_header(args, blk2->bp); xfs_dir3_leaf_check(dp, blk1->bp); xfs_dir3_leaf_check(dp, blk2->bp); /* * Mark whether we're inserting into the old or new leaf. */ if (hdr1.count < hdr2.count) state->inleaf = swap; else if (hdr1.count > hdr2.count) state->inleaf = !swap; else state->inleaf = swap ^ (blk1->index <= hdr1.count); /* * Adjust the expected index for insertion. */ if (!state->inleaf) blk2->index = blk1->index - hdr1.count; /* * Finally sanity check just to make sure we are not returning a * negative index */ if (blk2->index < 0) { state->inleaf = 1; blk2->index = 0; xfs_alert(dp->i_mount, "%s: picked the wrong leaf? reverting original leaf: blk1->index %d", __func__, blk1->index); } } static int xfs_dir3_data_block_free( xfs_da_args_t *args, struct xfs_dir2_data_hdr *hdr, struct xfs_dir2_free *free, xfs_dir2_db_t fdb, int findex, struct xfs_buf *fbp, int longest) { int logfree = 0; __be16 *bests; struct xfs_dir3_icfree_hdr freehdr; struct xfs_inode *dp = args->dp; dp->d_ops->free_hdr_from_disk(&freehdr, free); bests = dp->d_ops->free_bests_p(free); if (hdr) { /* * Data block is not empty, just set the free entry to the new * value. */ bests[findex] = cpu_to_be16(longest); xfs_dir2_free_log_bests(args, fbp, findex, findex); return 0; } /* One less used entry in the free table. */ freehdr.nused--; /* * If this was the last entry in the table, we can trim the table size * back. There might be other entries at the end referring to * non-existent data blocks, get those too. */ if (findex == freehdr.nvalid - 1) { int i; /* free entry index */ for (i = findex - 1; i >= 0; i--) { if (bests[i] != cpu_to_be16(NULLDATAOFF)) break; } freehdr.nvalid = i + 1; logfree = 0; } else { /* Not the last entry, just punch it out. */ bests[findex] = cpu_to_be16(NULLDATAOFF); logfree = 1; } dp->d_ops->free_hdr_to_disk(free, &freehdr); xfs_dir2_free_log_header(args, fbp); /* * If there are no useful entries left in the block, get rid of the * block if we can. */ if (!freehdr.nused) { int error; error = xfs_dir2_shrink_inode(args, fdb, fbp); if (error == 0) { fbp = NULL; logfree = 0; } else if (error != -ENOSPC || args->total != 0) return error; /* * It's possible to get ENOSPC if there is no * space reservation. In this case some one * else will eventually get rid of this block. */ } /* Log the free entry that changed, unless we got rid of it. */ if (logfree) xfs_dir2_free_log_bests(args, fbp, findex, findex); return 0; } /* * Remove an entry from a node directory. * This removes the leaf entry and the data entry, * and updates the free block if necessary. */ static int /* error */ xfs_dir2_leafn_remove( xfs_da_args_t *args, /* operation arguments */ struct xfs_buf *bp, /* leaf buffer */ int index, /* leaf entry index */ xfs_da_state_blk_t *dblk, /* data block */ int *rval) /* resulting block needs join */ { xfs_dir2_data_hdr_t *hdr; /* data block header */ xfs_dir2_db_t db; /* data block number */ struct xfs_buf *dbp; /* data block buffer */ xfs_dir2_data_entry_t *dep; /* data block entry */ xfs_inode_t *dp; /* incore directory inode */ xfs_dir2_leaf_t *leaf; /* leaf structure */ xfs_dir2_leaf_entry_t *lep; /* leaf entry */ int longest; /* longest data free entry */ int off; /* data block entry offset */ int needlog; /* need to log data header */ int needscan; /* need to rescan data frees */ xfs_trans_t *tp; /* transaction pointer */ struct xfs_dir2_data_free *bf; /* bestfree table */ struct xfs_dir3_icleaf_hdr leafhdr; struct xfs_dir2_leaf_entry *ents; trace_xfs_dir2_leafn_remove(args, index); dp = args->dp; tp = args->trans; leaf = bp->b_addr; dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf); ents = dp->d_ops->leaf_ents_p(leaf); /* * Point to the entry we're removing. */ lep = &ents[index]; /* * Extract the data block and offset from the entry. */ db = xfs_dir2_dataptr_to_db(args->geo, be32_to_cpu(lep->address)); ASSERT(dblk->blkno == db); off = xfs_dir2_dataptr_to_off(args->geo, be32_to_cpu(lep->address)); ASSERT(dblk->index == off); /* * Kill the leaf entry by marking it stale. * Log the leaf block changes. */ leafhdr.stale++; dp->d_ops->leaf_hdr_to_disk(leaf, &leafhdr); xfs_dir3_leaf_log_header(args, bp); lep->address = cpu_to_be32(XFS_DIR2_NULL_DATAPTR); xfs_dir3_leaf_log_ents(args, bp, index, index); /* * Make the data entry free. Keep track of the longest freespace * in the data block in case it changes. */ dbp = dblk->bp; hdr = dbp->b_addr; dep = (xfs_dir2_data_entry_t *)((char *)hdr + off); bf = dp->d_ops->data_bestfree_p(hdr); longest = be16_to_cpu(bf[0].length); needlog = needscan = 0; xfs_dir2_data_make_free(args, dbp, off, dp->d_ops->data_entsize(dep->namelen), &needlog, &needscan); /* * Rescan the data block freespaces for bestfree. * Log the data block header if needed. */ if (needscan) xfs_dir2_data_freescan(dp, hdr, &needlog); if (needlog) xfs_dir2_data_log_header(args, dbp); xfs_dir3_data_check(dp, dbp); /* * If the longest data block freespace changes, need to update * the corresponding freeblock entry. */ if (longest < be16_to_cpu(bf[0].length)) { int error; /* error return value */ struct xfs_buf *fbp; /* freeblock buffer */ xfs_dir2_db_t fdb; /* freeblock block number */ int findex; /* index in freeblock entries */ xfs_dir2_free_t *free; /* freeblock structure */ /* * Convert the data block number to a free block, * read in the free block. */ fdb = dp->d_ops->db_to_fdb(args->geo, db); error = xfs_dir2_free_read(tp, dp, xfs_dir2_db_to_da(args->geo, fdb), &fbp); if (error) return error; free = fbp->b_addr; #ifdef DEBUG { struct xfs_dir3_icfree_hdr freehdr; dp->d_ops->free_hdr_from_disk(&freehdr, free); ASSERT(freehdr.firstdb == dp->d_ops->free_max_bests(args->geo) * (fdb - xfs_dir2_byte_to_db(args->geo, XFS_DIR2_FREE_OFFSET))); } #endif /* * Calculate which entry we need to fix. */ findex = dp->d_ops->db_to_fdindex(args->geo, db); longest = be16_to_cpu(bf[0].length); /* * If the data block is now empty we can get rid of it * (usually). */ if (longest == args->geo->blksize - dp->d_ops->data_entry_offset) { /* * Try to punch out the data block. */ error = xfs_dir2_shrink_inode(args, db, dbp); if (error == 0) { dblk->bp = NULL; hdr = NULL; } /* * We can get ENOSPC if there's no space reservation. * In this case just drop the buffer and some one else * will eventually get rid of the empty block. */ else if (!(error == -ENOSPC && args->total == 0)) return error; } /* * If we got rid of the data block, we can eliminate that entry * in the free block. */ error = xfs_dir3_data_block_free(args, hdr, free, fdb, findex, fbp, longest); if (error) return error; } xfs_dir3_leaf_check(dp, bp); /* * Return indication of whether this leaf block is empty enough * to justify trying to join it with a neighbor. */ *rval = (dp->d_ops->leaf_hdr_size + (uint)sizeof(ents[0]) * (leafhdr.count - leafhdr.stale)) < args->geo->magicpct; return 0; } /* * Split the leaf entries in the old block into old and new blocks. */ int /* error */ xfs_dir2_leafn_split( xfs_da_state_t *state, /* btree cursor */ xfs_da_state_blk_t *oldblk, /* original block */ xfs_da_state_blk_t *newblk) /* newly created block */ { xfs_da_args_t *args; /* operation arguments */ xfs_dablk_t blkno; /* new leaf block number */ int error; /* error return value */ struct xfs_inode *dp; /* * Allocate space for a new leaf node. */ args = state->args; dp = args->dp; ASSERT(oldblk->magic == XFS_DIR2_LEAFN_MAGIC); error = xfs_da_grow_inode(args, &blkno); if (error) { return error; } /* * Initialize the new leaf block. */ error = xfs_dir3_leaf_get_buf(args, xfs_dir2_da_to_db(args->geo, blkno), &newblk->bp, XFS_DIR2_LEAFN_MAGIC); if (error) return error; newblk->blkno = blkno; newblk->magic = XFS_DIR2_LEAFN_MAGIC; /* * Rebalance the entries across the two leaves, link the new * block into the leaves. */ xfs_dir2_leafn_rebalance(state, oldblk, newblk); error = xfs_da3_blk_link(state, oldblk, newblk); if (error) { return error; } /* * Insert the new entry in the correct block. */ if (state->inleaf) error = xfs_dir2_leafn_add(oldblk->bp, args, oldblk->index); else error = xfs_dir2_leafn_add(newblk->bp, args, newblk->index); /* * Update last hashval in each block since we added the name. */ oldblk->hashval = xfs_dir2_leafn_lasthash(dp, oldblk->bp, NULL); newblk->hashval = xfs_dir2_leafn_lasthash(dp, newblk->bp, NULL); xfs_dir3_leaf_check(dp, oldblk->bp); xfs_dir3_leaf_check(dp, newblk->bp); return error; } /* * Check a leaf block and its neighbors to see if the block should be * collapsed into one or the other neighbor. Always keep the block * with the smaller block number. * If the current block is over 50% full, don't try to join it, return 0. * If the block is empty, fill in the state structure and return 2. * If it can be collapsed, fill in the state structure and return 1. * If nothing can be done, return 0. */ int /* error */ xfs_dir2_leafn_toosmall( xfs_da_state_t *state, /* btree cursor */ int *action) /* resulting action to take */ { xfs_da_state_blk_t *blk; /* leaf block */ xfs_dablk_t blkno; /* leaf block number */ struct xfs_buf *bp; /* leaf buffer */ int bytes; /* bytes in use */ int count; /* leaf live entry count */ int error; /* error return value */ int forward; /* sibling block direction */ int i; /* sibling counter */ xfs_dir2_leaf_t *leaf; /* leaf structure */ int rval; /* result from path_shift */ struct xfs_dir3_icleaf_hdr leafhdr; struct xfs_dir2_leaf_entry *ents; struct xfs_inode *dp = state->args->dp; /* * Check for the degenerate case of the block being over 50% full. * If so, it's not worth even looking to see if we might be able * to coalesce with a sibling. */ blk = &state->path.blk[state->path.active - 1]; leaf = blk->bp->b_addr; dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf); ents = dp->d_ops->leaf_ents_p(leaf); xfs_dir3_leaf_check(dp, blk->bp); count = leafhdr.count - leafhdr.stale; bytes = dp->d_ops->leaf_hdr_size + count * sizeof(ents[0]); if (bytes > (state->args->geo->blksize >> 1)) { /* * Blk over 50%, don't try to join. */ *action = 0; return 0; } /* * Check for the degenerate case of the block being empty. * If the block is empty, we'll simply delete it, no need to * coalesce it with a sibling block. We choose (arbitrarily) * to merge with the forward block unless it is NULL. */ if (count == 0) { /* * Make altpath point to the block we want to keep and * path point to the block we want to drop (this one). */ forward = (leafhdr.forw != 0); memcpy(&state->altpath, &state->path, sizeof(state->path)); error = xfs_da3_path_shift(state, &state->altpath, forward, 0, &rval); if (error) return error; *action = rval ? 2 : 0; return 0; } /* * Examine each sibling block to see if we can coalesce with * at least 25% free space to spare. We need to figure out * whether to merge with the forward or the backward block. * We prefer coalescing with the lower numbered sibling so as * to shrink a directory over time. */ forward = leafhdr.forw < leafhdr.back; for (i = 0, bp = NULL; i < 2; forward = !forward, i++) { struct xfs_dir3_icleaf_hdr hdr2; blkno = forward ? leafhdr.forw : leafhdr.back; if (blkno == 0) continue; /* * Read the sibling leaf block. */ error = xfs_dir3_leafn_read(state->args->trans, dp, blkno, -1, &bp); if (error) return error; /* * Count bytes in the two blocks combined. */ count = leafhdr.count - leafhdr.stale; bytes = state->args->geo->blksize - (state->args->geo->blksize >> 2); leaf = bp->b_addr; dp->d_ops->leaf_hdr_from_disk(&hdr2, leaf); ents = dp->d_ops->leaf_ents_p(leaf); count += hdr2.count - hdr2.stale; bytes -= count * sizeof(ents[0]); /* * Fits with at least 25% to spare. */ if (bytes >= 0) break; xfs_trans_brelse(state->args->trans, bp); } /* * Didn't like either block, give up. */ if (i >= 2) { *action = 0; return 0; } /* * Make altpath point to the block we want to keep (the lower * numbered block) and path point to the block we want to drop. */ memcpy(&state->altpath, &state->path, sizeof(state->path)); if (blkno < blk->blkno) error = xfs_da3_path_shift(state, &state->altpath, forward, 0, &rval); else error = xfs_da3_path_shift(state, &state->path, forward, 0, &rval); if (error) { return error; } *action = rval ? 0 : 1; return 0; } /* * Move all the leaf entries from drop_blk to save_blk. * This is done as part of a join operation. */ void xfs_dir2_leafn_unbalance( xfs_da_state_t *state, /* cursor */ xfs_da_state_blk_t *drop_blk, /* dead block */ xfs_da_state_blk_t *save_blk) /* surviving block */ { xfs_da_args_t *args; /* operation arguments */ xfs_dir2_leaf_t *drop_leaf; /* dead leaf structure */ xfs_dir2_leaf_t *save_leaf; /* surviving leaf structure */ struct xfs_dir3_icleaf_hdr savehdr; struct xfs_dir3_icleaf_hdr drophdr; struct xfs_dir2_leaf_entry *sents; struct xfs_dir2_leaf_entry *dents; struct xfs_inode *dp = state->args->dp; args = state->args; ASSERT(drop_blk->magic == XFS_DIR2_LEAFN_MAGIC); ASSERT(save_blk->magic == XFS_DIR2_LEAFN_MAGIC); drop_leaf = drop_blk->bp->b_addr; save_leaf = save_blk->bp->b_addr; dp->d_ops->leaf_hdr_from_disk(&savehdr, save_leaf); dp->d_ops->leaf_hdr_from_disk(&drophdr, drop_leaf); sents = dp->d_ops->leaf_ents_p(save_leaf); dents = dp->d_ops->leaf_ents_p(drop_leaf); /* * If there are any stale leaf entries, take this opportunity * to purge them. */ if (drophdr.stale) xfs_dir3_leaf_compact(args, &drophdr, drop_blk->bp); if (savehdr.stale) xfs_dir3_leaf_compact(args, &savehdr, save_blk->bp); /* * Move the entries from drop to the appropriate end of save. */ drop_blk->hashval = be32_to_cpu(dents[drophdr.count - 1].hashval); if (xfs_dir2_leafn_order(dp, save_blk->bp, drop_blk->bp)) xfs_dir3_leafn_moveents(args, drop_blk->bp, &drophdr, dents, 0, save_blk->bp, &savehdr, sents, 0, drophdr.count); else xfs_dir3_leafn_moveents(args, drop_blk->bp, &drophdr, dents, 0, save_blk->bp, &savehdr, sents, savehdr.count, drophdr.count); save_blk->hashval = be32_to_cpu(sents[savehdr.count - 1].hashval); /* log the changes made when moving the entries */ dp->d_ops->leaf_hdr_to_disk(save_leaf, &savehdr); dp->d_ops->leaf_hdr_to_disk(drop_leaf, &drophdr); xfs_dir3_leaf_log_header(args, save_blk->bp); xfs_dir3_leaf_log_header(args, drop_blk->bp); xfs_dir3_leaf_check(dp, save_blk->bp); xfs_dir3_leaf_check(dp, drop_blk->bp); } /* * Top-level node form directory addname routine. */ int /* error */ xfs_dir2_node_addname( xfs_da_args_t *args) /* operation arguments */ { xfs_da_state_blk_t *blk; /* leaf block for insert */ int error; /* error return value */ int rval; /* sub-return value */ xfs_da_state_t *state; /* btree cursor */ trace_xfs_dir2_node_addname(args); /* * Allocate and initialize the state (btree cursor). */ state = xfs_da_state_alloc(); state->args = args; state->mp = args->dp->i_mount; /* * Look up the name. We're not supposed to find it, but * this gives us the insertion point. */ error = xfs_da3_node_lookup_int(state, &rval); if (error) rval = error; if (rval != -ENOENT) { goto done; } /* * Add the data entry to a data block. * Extravalid is set to a freeblock found by lookup. */ rval = xfs_dir2_node_addname_int(args, state->extravalid ? &state->extrablk : NULL); if (rval) { goto done; } blk = &state->path.blk[state->path.active - 1]; ASSERT(blk->magic == XFS_DIR2_LEAFN_MAGIC); /* * Add the new leaf entry. */ rval = xfs_dir2_leafn_add(blk->bp, args, blk->index); if (rval == 0) { /* * It worked, fix the hash values up the btree. */ if (!(args->op_flags & XFS_DA_OP_JUSTCHECK)) xfs_da3_fixhashpath(state, &state->path); } else { /* * It didn't work, we need to split the leaf block. */ if (args->total == 0) { ASSERT(rval == -ENOSPC); goto done; } /* * Split the leaf block and insert the new entry. */ rval = xfs_da3_split(state); } done: xfs_da_state_free(state); return rval; } /* * Add the data entry for a node-format directory name addition. * The leaf entry is added in xfs_dir2_leafn_add. * We may enter with a freespace block that the lookup found. */ static int /* error */ xfs_dir2_node_addname_int( xfs_da_args_t *args, /* operation arguments */ xfs_da_state_blk_t *fblk) /* optional freespace block */ { xfs_dir2_data_hdr_t *hdr; /* data block header */ xfs_dir2_db_t dbno; /* data block number */ struct xfs_buf *dbp; /* data block buffer */ xfs_dir2_data_entry_t *dep; /* data entry pointer */ xfs_inode_t *dp; /* incore directory inode */ xfs_dir2_data_unused_t *dup; /* data unused entry pointer */ int error; /* error return value */ xfs_dir2_db_t fbno; /* freespace block number */ struct xfs_buf *fbp; /* freespace buffer */ int findex; /* freespace entry index */ xfs_dir2_free_t *free=NULL; /* freespace block structure */ xfs_dir2_db_t ifbno; /* initial freespace block no */ xfs_dir2_db_t lastfbno=0; /* highest freespace block no */ int length; /* length of the new entry */ int logfree; /* need to log free entry */ xfs_mount_t *mp; /* filesystem mount point */ int needlog; /* need to log data header */ int needscan; /* need to rescan data frees */ __be16 *tagp; /* data entry tag pointer */ xfs_trans_t *tp; /* transaction pointer */ __be16 *bests; struct xfs_dir3_icfree_hdr freehdr; struct xfs_dir2_data_free *bf; dp = args->dp; mp = dp->i_mount; tp = args->trans; length = dp->d_ops->data_entsize(args->namelen); /* * If we came in with a freespace block that means that lookup * found an entry with our hash value. This is the freespace * block for that data entry. */ if (fblk) { fbp = fblk->bp; /* * Remember initial freespace block number. */ ifbno = fblk->blkno; free = fbp->b_addr; findex = fblk->index; bests = dp->d_ops->free_bests_p(free); dp->d_ops->free_hdr_from_disk(&freehdr, free); /* * This means the free entry showed that the data block had * space for our entry, so we remembered it. * Use that data block. */ if (findex >= 0) { ASSERT(findex < freehdr.nvalid); ASSERT(be16_to_cpu(bests[findex]) != NULLDATAOFF); ASSERT(be16_to_cpu(bests[findex]) >= length); dbno = freehdr.firstdb + findex; } else { /* * The data block looked at didn't have enough room. * We'll start at the beginning of the freespace entries. */ dbno = -1; findex = 0; } } else { /* * Didn't come in with a freespace block, so no data block. */ ifbno = dbno = -1; fbp = NULL; findex = 0; } /* * If we don't have a data block yet, we're going to scan the * freespace blocks looking for one. Figure out what the * highest freespace block number is. */ if (dbno == -1) { xfs_fileoff_t fo; /* freespace block number */ if ((error = xfs_bmap_last_offset(dp, &fo, XFS_DATA_FORK))) return error; lastfbno = xfs_dir2_da_to_db(args->geo, (xfs_dablk_t)fo); fbno = ifbno; } /* * While we haven't identified a data block, search the freeblock * data for a good data block. If we find a null freeblock entry, * indicating a hole in the data blocks, remember that. */ while (dbno == -1) { /* * If we don't have a freeblock in hand, get the next one. */ if (fbp == NULL) { /* * Happens the first time through unless lookup gave * us a freespace block to start with. */ if (++fbno == 0) fbno = xfs_dir2_byte_to_db(args->geo, XFS_DIR2_FREE_OFFSET); /* * If it's ifbno we already looked at it. */ if (fbno == ifbno) fbno++; /* * If it's off the end we're done. */ if (fbno >= lastfbno) break; /* * Read the block. There can be holes in the * freespace blocks, so this might not succeed. * This should be really rare, so there's no reason * to avoid it. */ error = xfs_dir2_free_try_read(tp, dp, xfs_dir2_db_to_da(args->geo, fbno), &fbp); if (error) return error; if (!fbp) continue; free = fbp->b_addr; findex = 0; } /* * Look at the current free entry. Is it good enough? * * The bests initialisation should be where the bufer is read in * the above branch. But gcc is too stupid to realise that bests * and the freehdr are actually initialised if they are placed * there, so we have to do it here to avoid warnings. Blech. */ bests = dp->d_ops->free_bests_p(free); dp->d_ops->free_hdr_from_disk(&freehdr, free); if (be16_to_cpu(bests[findex]) != NULLDATAOFF && be16_to_cpu(bests[findex]) >= length) dbno = freehdr.firstdb + findex; else { /* * Are we done with the freeblock? */ if (++findex == freehdr.nvalid) { /* * Drop the block. */ xfs_trans_brelse(tp, fbp); fbp = NULL; if (fblk && fblk->bp) fblk->bp = NULL; } } } /* * If we don't have a data block, we need to allocate one and make * the freespace entries refer to it. */ if (unlikely(dbno == -1)) { /* * Not allowed to allocate, return failure. */ if ((args->op_flags & XFS_DA_OP_JUSTCHECK) || args->total == 0) return -ENOSPC; /* * Allocate and initialize the new data block. */ if (unlikely((error = xfs_dir2_grow_inode(args, XFS_DIR2_DATA_SPACE, &dbno)) || (error = xfs_dir3_data_init(args, dbno, &dbp)))) return error; /* * If (somehow) we have a freespace block, get rid of it. */ if (fbp) xfs_trans_brelse(tp, fbp); if (fblk && fblk->bp) fblk->bp = NULL; /* * Get the freespace block corresponding to the data block * that was just allocated. */ fbno = dp->d_ops->db_to_fdb(args->geo, dbno); error = xfs_dir2_free_try_read(tp, dp, xfs_dir2_db_to_da(args->geo, fbno), &fbp); if (error) return error; /* * If there wasn't a freespace block, the read will * return a NULL fbp. Allocate and initialize a new one. */ if (!fbp) { error = xfs_dir2_grow_inode(args, XFS_DIR2_FREE_SPACE, &fbno); if (error) return error; if (dp->d_ops->db_to_fdb(args->geo, dbno) != fbno) { xfs_alert(mp, "%s: dir ino %llu needed freesp block %lld for data block %lld, got %lld ifbno %llu lastfbno %d", __func__, (unsigned long long)dp->i_ino, (long long)dp->d_ops->db_to_fdb( args->geo, dbno), (long long)dbno, (long long)fbno, (unsigned long long)ifbno, lastfbno); if (fblk) { xfs_alert(mp, " fblk 0x%p blkno %llu index %d magic 0x%x", fblk, (unsigned long long)fblk->blkno, fblk->index, fblk->magic); } else { xfs_alert(mp, " ... fblk is NULL"); } XFS_ERROR_REPORT("xfs_dir2_node_addname_int", XFS_ERRLEVEL_LOW, mp); return -EFSCORRUPTED; } /* * Get a buffer for the new block. */ error = xfs_dir3_free_get_buf(args, fbno, &fbp); if (error) return error; free = fbp->b_addr; bests = dp->d_ops->free_bests_p(free); dp->d_ops->free_hdr_from_disk(&freehdr, free); /* * Remember the first slot as our empty slot. */ freehdr.firstdb = (fbno - xfs_dir2_byte_to_db(args->geo, XFS_DIR2_FREE_OFFSET)) * dp->d_ops->free_max_bests(args->geo); } else { free = fbp->b_addr; bests = dp->d_ops->free_bests_p(free); dp->d_ops->free_hdr_from_disk(&freehdr, free); } /* * Set the freespace block index from the data block number. */ findex = dp->d_ops->db_to_fdindex(args->geo, dbno); /* * If it's after the end of the current entries in the * freespace block, extend that table. */ if (findex >= freehdr.nvalid) { ASSERT(findex < dp->d_ops->free_max_bests(args->geo)); freehdr.nvalid = findex + 1; /* * Tag new entry so nused will go up. */ bests[findex] = cpu_to_be16(NULLDATAOFF); } /* * If this entry was for an empty data block * (this should always be true) then update the header. */ if (bests[findex] == cpu_to_be16(NULLDATAOFF)) { freehdr.nused++; dp->d_ops->free_hdr_to_disk(fbp->b_addr, &freehdr); xfs_dir2_free_log_header(args, fbp); } /* * Update the real value in the table. * We haven't allocated the data entry yet so this will * change again. */ hdr = dbp->b_addr; bf = dp->d_ops->data_bestfree_p(hdr); bests[findex] = bf[0].length; logfree = 1; } /* * We had a data block so we don't have to make a new one. */ else { /* * If just checking, we succeeded. */ if (args->op_flags & XFS_DA_OP_JUSTCHECK) return 0; /* * Read the data block in. */ error = xfs_dir3_data_read(tp, dp, xfs_dir2_db_to_da(args->geo, dbno), -1, &dbp); if (error) return error; hdr = dbp->b_addr; bf = dp->d_ops->data_bestfree_p(hdr); logfree = 0; } ASSERT(be16_to_cpu(bf[0].length) >= length); /* * Point to the existing unused space. */ dup = (xfs_dir2_data_unused_t *) ((char *)hdr + be16_to_cpu(bf[0].offset)); needscan = needlog = 0; /* * Mark the first part of the unused space, inuse for us. */ xfs_dir2_data_use_free(args, dbp, dup, (xfs_dir2_data_aoff_t)((char *)dup - (char *)hdr), length, &needlog, &needscan); /* * Fill in the new entry and log it. */ dep = (xfs_dir2_data_entry_t *)dup; dep->inumber = cpu_to_be64(args->inumber); dep->namelen = args->namelen; memcpy(dep->name, args->name, dep->namelen); dp->d_ops->data_put_ftype(dep, args->filetype); tagp = dp->d_ops->data_entry_tag_p(dep); *tagp = cpu_to_be16((char *)dep - (char *)hdr); xfs_dir2_data_log_entry(args, dbp, dep); /* * Rescan the block for bestfree if needed. */ if (needscan) xfs_dir2_data_freescan(dp, hdr, &needlog); /* * Log the data block header if needed. */ if (needlog) xfs_dir2_data_log_header(args, dbp); /* * If the freespace entry is now wrong, update it. */ bests = dp->d_ops->free_bests_p(free); /* gcc is so stupid */ if (be16_to_cpu(bests[findex]) != be16_to_cpu(bf[0].length)) { bests[findex] = bf[0].length; logfree = 1; } /* * Log the freespace entry if needed. */ if (logfree) xfs_dir2_free_log_bests(args, fbp, findex, findex); /* * Return the data block and offset in args, then drop the data block. */ args->blkno = (xfs_dablk_t)dbno; args->index = be16_to_cpu(*tagp); return 0; } /* * Lookup an entry in a node-format directory. * All the real work happens in xfs_da3_node_lookup_int. * The only real output is the inode number of the entry. */ int /* error */ xfs_dir2_node_lookup( xfs_da_args_t *args) /* operation arguments */ { int error; /* error return value */ int i; /* btree level */ int rval; /* operation return value */ xfs_da_state_t *state; /* btree cursor */ trace_xfs_dir2_node_lookup(args); /* * Allocate and initialize the btree cursor. */ state = xfs_da_state_alloc(); state->args = args; state->mp = args->dp->i_mount; /* * Fill in the path to the entry in the cursor. */ error = xfs_da3_node_lookup_int(state, &rval); if (error) rval = error; else if (rval == -ENOENT && args->cmpresult == XFS_CMP_CASE) { /* If a CI match, dup the actual name and return -EEXIST */ xfs_dir2_data_entry_t *dep; dep = (xfs_dir2_data_entry_t *) ((char *)state->extrablk.bp->b_addr + state->extrablk.index); rval = xfs_dir_cilookup_result(args, dep->name, dep->namelen); } /* * Release the btree blocks and leaf block. */ for (i = 0; i < state->path.active; i++) { xfs_trans_brelse(args->trans, state->path.blk[i].bp); state->path.blk[i].bp = NULL; } /* * Release the data block if we have it. */ if (state->extravalid && state->extrablk.bp) { xfs_trans_brelse(args->trans, state->extrablk.bp); state->extrablk.bp = NULL; } xfs_da_state_free(state); return rval; } /* * Remove an entry from a node-format directory. */ int /* error */ xfs_dir2_node_removename( struct xfs_da_args *args) /* operation arguments */ { struct xfs_da_state_blk *blk; /* leaf block */ int error; /* error return value */ int rval; /* operation return value */ struct xfs_da_state *state; /* btree cursor */ trace_xfs_dir2_node_removename(args); /* * Allocate and initialize the btree cursor. */ state = xfs_da_state_alloc(); state->args = args; state->mp = args->dp->i_mount; /* Look up the entry we're deleting, set up the cursor. */ error = xfs_da3_node_lookup_int(state, &rval); if (error) goto out_free; /* Didn't find it, upper layer screwed up. */ if (rval != -EEXIST) { error = rval; goto out_free; } blk = &state->path.blk[state->path.active - 1]; ASSERT(blk->magic == XFS_DIR2_LEAFN_MAGIC); ASSERT(state->extravalid); /* * Remove the leaf and data entries. * Extrablk refers to the data block. */ error = xfs_dir2_leafn_remove(args, blk->bp, blk->index, &state->extrablk, &rval); if (error) goto out_free; /* * Fix the hash values up the btree. */ xfs_da3_fixhashpath(state, &state->path); /* * If we need to join leaf blocks, do it. */ if (rval && state->path.active > 1) error = xfs_da3_join(state); /* * If no errors so far, try conversion to leaf format. */ if (!error) error = xfs_dir2_node_to_leaf(state); out_free: xfs_da_state_free(state); return error; } /* * Replace an entry's inode number in a node-format directory. */ int /* error */ xfs_dir2_node_replace( xfs_da_args_t *args) /* operation arguments */ { xfs_da_state_blk_t *blk; /* leaf block */ xfs_dir2_data_hdr_t *hdr; /* data block header */ xfs_dir2_data_entry_t *dep; /* data entry changed */ int error; /* error return value */ int i; /* btree level */ xfs_ino_t inum; /* new inode number */ int ftype; /* new file type */ xfs_dir2_leaf_t *leaf; /* leaf structure */ xfs_dir2_leaf_entry_t *lep; /* leaf entry being changed */ int rval; /* internal return value */ xfs_da_state_t *state; /* btree cursor */ trace_xfs_dir2_node_replace(args); /* * Allocate and initialize the btree cursor. */ state = xfs_da_state_alloc(); state->args = args; state->mp = args->dp->i_mount; /* * We have to save new inode number and ftype since * xfs_da3_node_lookup_int() is going to overwrite them */ inum = args->inumber; ftype = args->filetype; /* * Lookup the entry to change in the btree. */ error = xfs_da3_node_lookup_int(state, &rval); if (error) { rval = error; } /* * It should be found, since the vnodeops layer has looked it up * and locked it. But paranoia is good. */ if (rval == -EEXIST) { struct xfs_dir2_leaf_entry *ents; /* * Find the leaf entry. */ blk = &state->path.blk[state->path.active - 1]; ASSERT(blk->magic == XFS_DIR2_LEAFN_MAGIC); leaf = blk->bp->b_addr; ents = args->dp->d_ops->leaf_ents_p(leaf); lep = &ents[blk->index]; ASSERT(state->extravalid); /* * Point to the data entry. */ hdr = state->extrablk.bp->b_addr; ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC)); dep = (xfs_dir2_data_entry_t *) ((char *)hdr + xfs_dir2_dataptr_to_off(args->geo, be32_to_cpu(lep->address))); ASSERT(inum != be64_to_cpu(dep->inumber)); /* * Fill in the new inode number and log the entry. */ dep->inumber = cpu_to_be64(inum); args->dp->d_ops->data_put_ftype(dep, ftype); xfs_dir2_data_log_entry(args, state->extrablk.bp, dep); rval = 0; } /* * Didn't find it, and we're holding a data block. Drop it. */ else if (state->extravalid) { xfs_trans_brelse(args->trans, state->extrablk.bp); state->extrablk.bp = NULL; } /* * Release all the buffers in the cursor. */ for (i = 0; i < state->path.active; i++) { xfs_trans_brelse(args->trans, state->path.blk[i].bp); state->path.blk[i].bp = NULL; } xfs_da_state_free(state); return rval; } /* * Trim off a trailing empty freespace block. * Return (in rvalp) 1 if we did it, 0 if not. */ int /* error */ xfs_dir2_node_trim_free( xfs_da_args_t *args, /* operation arguments */ xfs_fileoff_t fo, /* free block number */ int *rvalp) /* out: did something */ { struct xfs_buf *bp; /* freespace buffer */ xfs_inode_t *dp; /* incore directory inode */ int error; /* error return code */ xfs_dir2_free_t *free; /* freespace structure */ xfs_trans_t *tp; /* transaction pointer */ struct xfs_dir3_icfree_hdr freehdr; dp = args->dp; tp = args->trans; /* * Read the freespace block. */ error = xfs_dir2_free_try_read(tp, dp, fo, &bp); if (error) return error; /* * There can be holes in freespace. If fo is a hole, there's * nothing to do. */ if (!bp) return 0; free = bp->b_addr; dp->d_ops->free_hdr_from_disk(&freehdr, free); /* * If there are used entries, there's nothing to do. */ if (freehdr.nused > 0) { xfs_trans_brelse(tp, bp); *rvalp = 0; return 0; } /* * Blow the block away. */ error = xfs_dir2_shrink_inode(args, xfs_dir2_da_to_db(args->geo, (xfs_dablk_t)fo), bp); if (error) { /* * Can't fail with ENOSPC since that only happens with no * space reservation, when breaking up an extent into two * pieces. This is the last block of an extent. */ ASSERT(error != -ENOSPC); xfs_trans_brelse(tp, bp); return error; } /* * Return that we succeeded. */ *rvalp = 1; return 0; } partclone-0.2.86/src/xfs/xfs_dir2_priv.h000066400000000000000000000134631262102574200201260ustar00rootroot00000000000000/* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __XFS_DIR2_PRIV_H__ #define __XFS_DIR2_PRIV_H__ struct dir_context; /* xfs_dir2.c */ extern int xfs_dir2_grow_inode(struct xfs_da_args *args, int space, xfs_dir2_db_t *dbp); extern int xfs_dir_cilookup_result(struct xfs_da_args *args, const unsigned char *name, int len); /* xfs_dir2_block.c */ extern int xfs_dir3_block_read(struct xfs_trans *tp, struct xfs_inode *dp, struct xfs_buf **bpp); extern int xfs_dir2_block_addname(struct xfs_da_args *args); extern int xfs_dir2_block_lookup(struct xfs_da_args *args); extern int xfs_dir2_block_removename(struct xfs_da_args *args); extern int xfs_dir2_block_replace(struct xfs_da_args *args); extern int xfs_dir2_leaf_to_block(struct xfs_da_args *args, struct xfs_buf *lbp, struct xfs_buf *dbp); /* xfs_dir2_data.c */ #ifdef DEBUG #define xfs_dir3_data_check(dp,bp) __xfs_dir3_data_check(dp, bp); #else #define xfs_dir3_data_check(dp,bp) #endif extern int __xfs_dir3_data_check(struct xfs_inode *dp, struct xfs_buf *bp); extern int xfs_dir3_data_read(struct xfs_trans *tp, struct xfs_inode *dp, xfs_dablk_t bno, xfs_daddr_t mapped_bno, struct xfs_buf **bpp); extern int xfs_dir3_data_readahead(struct xfs_inode *dp, xfs_dablk_t bno, xfs_daddr_t mapped_bno); extern struct xfs_dir2_data_free * xfs_dir2_data_freeinsert(struct xfs_dir2_data_hdr *hdr, struct xfs_dir2_data_free *bf, struct xfs_dir2_data_unused *dup, int *loghead); extern int xfs_dir3_data_init(struct xfs_da_args *args, xfs_dir2_db_t blkno, struct xfs_buf **bpp); /* xfs_dir2_leaf.c */ extern int xfs_dir3_leafn_read(struct xfs_trans *tp, struct xfs_inode *dp, xfs_dablk_t fbno, xfs_daddr_t mappedbno, struct xfs_buf **bpp); extern int xfs_dir2_block_to_leaf(struct xfs_da_args *args, struct xfs_buf *dbp); extern int xfs_dir2_leaf_addname(struct xfs_da_args *args); extern void xfs_dir3_leaf_compact(struct xfs_da_args *args, struct xfs_dir3_icleaf_hdr *leafhdr, struct xfs_buf *bp); extern void xfs_dir3_leaf_compact_x1(struct xfs_dir3_icleaf_hdr *leafhdr, struct xfs_dir2_leaf_entry *ents, int *indexp, int *lowstalep, int *highstalep, int *lowlogp, int *highlogp); extern int xfs_dir3_leaf_get_buf(struct xfs_da_args *args, xfs_dir2_db_t bno, struct xfs_buf **bpp, __uint16_t magic); extern void xfs_dir3_leaf_log_ents(struct xfs_da_args *args, struct xfs_buf *bp, int first, int last); extern void xfs_dir3_leaf_log_header(struct xfs_da_args *args, struct xfs_buf *bp); extern int xfs_dir2_leaf_lookup(struct xfs_da_args *args); extern int xfs_dir2_leaf_removename(struct xfs_da_args *args); extern int xfs_dir2_leaf_replace(struct xfs_da_args *args); extern int xfs_dir2_leaf_search_hash(struct xfs_da_args *args, struct xfs_buf *lbp); extern int xfs_dir2_leaf_trim_data(struct xfs_da_args *args, struct xfs_buf *lbp, xfs_dir2_db_t db); extern struct xfs_dir2_leaf_entry * xfs_dir3_leaf_find_entry(struct xfs_dir3_icleaf_hdr *leafhdr, struct xfs_dir2_leaf_entry *ents, int index, int compact, int lowstale, int highstale, int *lfloglow, int *lfloghigh); extern int xfs_dir2_node_to_leaf(struct xfs_da_state *state); extern bool xfs_dir3_leaf_check_int(struct xfs_mount *mp, struct xfs_inode *dp, struct xfs_dir3_icleaf_hdr *hdr, struct xfs_dir2_leaf *leaf); /* xfs_dir2_node.c */ extern int xfs_dir2_leaf_to_node(struct xfs_da_args *args, struct xfs_buf *lbp); extern xfs_dahash_t xfs_dir2_leafn_lasthash(struct xfs_inode *dp, struct xfs_buf *bp, int *count); extern int xfs_dir2_leafn_lookup_int(struct xfs_buf *bp, struct xfs_da_args *args, int *indexp, struct xfs_da_state *state); extern int xfs_dir2_leafn_order(struct xfs_inode *dp, struct xfs_buf *leaf1_bp, struct xfs_buf *leaf2_bp); extern int xfs_dir2_leafn_split(struct xfs_da_state *state, struct xfs_da_state_blk *oldblk, struct xfs_da_state_blk *newblk); extern int xfs_dir2_leafn_toosmall(struct xfs_da_state *state, int *action); extern void xfs_dir2_leafn_unbalance(struct xfs_da_state *state, struct xfs_da_state_blk *drop_blk, struct xfs_da_state_blk *save_blk); extern int xfs_dir2_node_addname(struct xfs_da_args *args); extern int xfs_dir2_node_lookup(struct xfs_da_args *args); extern int xfs_dir2_node_removename(struct xfs_da_args *args); extern int xfs_dir2_node_replace(struct xfs_da_args *args); extern int xfs_dir2_node_trim_free(struct xfs_da_args *args, xfs_fileoff_t fo, int *rvalp); extern int xfs_dir2_free_read(struct xfs_trans *tp, struct xfs_inode *dp, xfs_dablk_t fbno, struct xfs_buf **bpp); /* xfs_dir2_sf.c */ extern int xfs_dir2_block_sfsize(struct xfs_inode *dp, struct xfs_dir2_data_hdr *block, struct xfs_dir2_sf_hdr *sfhp); extern int xfs_dir2_block_to_sf(struct xfs_da_args *args, struct xfs_buf *bp, int size, xfs_dir2_sf_hdr_t *sfhp); extern int xfs_dir2_sf_addname(struct xfs_da_args *args); extern int xfs_dir2_sf_create(struct xfs_da_args *args, xfs_ino_t pino); extern int xfs_dir2_sf_lookup(struct xfs_da_args *args); extern int xfs_dir2_sf_removename(struct xfs_da_args *args); extern int xfs_dir2_sf_replace(struct xfs_da_args *args); /* xfs_dir2_readdir.c */ extern int xfs_readdir(struct xfs_inode *dp, struct dir_context *ctx, size_t bufsize); #endif /* __XFS_DIR2_PRIV_H__ */ partclone-0.2.86/src/xfs/xfs_dir2_sf.c000066400000000000000000001026471262102574200175540ustar00rootroot00000000000000/* * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_mount.h" #include "xfs_da_format.h" #include "xfs_da_btree.h" #include "xfs_inode.h" #include "xfs_trans.h" #include "xfs_dir2.h" #include "xfs_dir2_priv.h" #include "xfs_trace.h" /* * Prototypes for internal functions. */ static void xfs_dir2_sf_addname_easy(xfs_da_args_t *args, xfs_dir2_sf_entry_t *sfep, xfs_dir2_data_aoff_t offset, int new_isize); static void xfs_dir2_sf_addname_hard(xfs_da_args_t *args, int objchange, int new_isize); static int xfs_dir2_sf_addname_pick(xfs_da_args_t *args, int objchange, xfs_dir2_sf_entry_t **sfepp, xfs_dir2_data_aoff_t *offsetp); #ifdef DEBUG static void xfs_dir2_sf_check(xfs_da_args_t *args); #else #define xfs_dir2_sf_check(args) #endif /* DEBUG */ static void xfs_dir2_sf_toino4(xfs_da_args_t *args); static void xfs_dir2_sf_toino8(xfs_da_args_t *args); /* * Given a block directory (dp/block), calculate its size as a shortform (sf) * directory and a header for the sf directory, if it will fit it the * space currently present in the inode. If it won't fit, the output * size is too big (but not accurate). */ int /* size for sf form */ xfs_dir2_block_sfsize( xfs_inode_t *dp, /* incore inode pointer */ xfs_dir2_data_hdr_t *hdr, /* block directory data */ xfs_dir2_sf_hdr_t *sfhp) /* output: header for sf form */ { xfs_dir2_dataptr_t addr; /* data entry address */ xfs_dir2_leaf_entry_t *blp; /* leaf area of the block */ xfs_dir2_block_tail_t *btp; /* tail area of the block */ int count; /* shortform entry count */ xfs_dir2_data_entry_t *dep; /* data entry in the block */ int i; /* block entry index */ int i8count; /* count of big-inode entries */ int isdot; /* entry is "." */ int isdotdot; /* entry is ".." */ xfs_mount_t *mp; /* mount structure pointer */ int namelen; /* total name bytes */ xfs_ino_t parent = 0; /* parent inode number */ int size=0; /* total computed size */ int has_ftype; struct xfs_da_geometry *geo; mp = dp->i_mount; geo = mp->m_dir_geo; /* * if there is a filetype field, add the extra byte to the namelen * for each entry that we see. */ has_ftype = xfs_sb_version_hasftype(&mp->m_sb) ? 1 : 0; count = i8count = namelen = 0; btp = xfs_dir2_block_tail_p(geo, hdr); blp = xfs_dir2_block_leaf_p(btp); /* * Iterate over the block's data entries by using the leaf pointers. */ for (i = 0; i < be32_to_cpu(btp->count); i++) { if ((addr = be32_to_cpu(blp[i].address)) == XFS_DIR2_NULL_DATAPTR) continue; /* * Calculate the pointer to the entry at hand. */ dep = (xfs_dir2_data_entry_t *)((char *)hdr + xfs_dir2_dataptr_to_off(geo, addr)); /* * Detect . and .., so we can special-case them. * . is not included in sf directories. * .. is included by just the parent inode number. */ isdot = dep->namelen == 1 && dep->name[0] == '.'; isdotdot = dep->namelen == 2 && dep->name[0] == '.' && dep->name[1] == '.'; if (!isdot) i8count += be64_to_cpu(dep->inumber) > XFS_DIR2_MAX_SHORT_INUM; /* take into account the file type field */ if (!isdot && !isdotdot) { count++; namelen += dep->namelen + has_ftype; } else if (isdotdot) parent = be64_to_cpu(dep->inumber); /* * Calculate the new size, see if we should give up yet. */ size = xfs_dir2_sf_hdr_size(i8count) + /* header */ count + /* namelen */ count * (uint)sizeof(xfs_dir2_sf_off_t) + /* offset */ namelen + /* name */ (i8count ? /* inumber */ (uint)sizeof(xfs_dir2_ino8_t) * count : (uint)sizeof(xfs_dir2_ino4_t) * count); if (size > XFS_IFORK_DSIZE(dp)) return size; /* size value is a failure */ } /* * Create the output header, if it worked. */ sfhp->count = count; sfhp->i8count = i8count; dp->d_ops->sf_put_parent_ino(sfhp, parent); return size; } /* * Convert a block format directory to shortform. * Caller has already checked that it will fit, and built us a header. */ int /* error */ xfs_dir2_block_to_sf( xfs_da_args_t *args, /* operation arguments */ struct xfs_buf *bp, int size, /* shortform directory size */ xfs_dir2_sf_hdr_t *sfhp) /* shortform directory hdr */ { xfs_dir2_data_hdr_t *hdr; /* block header */ xfs_dir2_block_tail_t *btp; /* block tail pointer */ xfs_dir2_data_entry_t *dep; /* data entry pointer */ xfs_inode_t *dp; /* incore directory inode */ xfs_dir2_data_unused_t *dup; /* unused data pointer */ char *endptr; /* end of data entries */ int error; /* error return value */ int logflags; /* inode logging flags */ xfs_mount_t *mp; /* filesystem mount point */ char *ptr; /* current data pointer */ xfs_dir2_sf_entry_t *sfep; /* shortform entry */ xfs_dir2_sf_hdr_t *sfp; /* shortform directory header */ xfs_dir2_sf_hdr_t *dst; /* temporary data buffer */ trace_xfs_dir2_block_to_sf(args); dp = args->dp; mp = dp->i_mount; /* * allocate a temporary destination buffer the size of the inode * to format the data into. Once we have formatted the data, we * can free the block and copy the formatted data into the inode literal * area. */ dst = kmem_alloc(mp->m_sb.sb_inodesize, KM_SLEEP); hdr = bp->b_addr; /* * Copy the header into the newly allocate local space. */ sfp = (xfs_dir2_sf_hdr_t *)dst; memcpy(sfp, sfhp, xfs_dir2_sf_hdr_size(sfhp->i8count)); /* * Set up to loop over the block's entries. */ btp = xfs_dir2_block_tail_p(args->geo, hdr); ptr = (char *)dp->d_ops->data_entry_p(hdr); endptr = (char *)xfs_dir2_block_leaf_p(btp); sfep = xfs_dir2_sf_firstentry(sfp); /* * Loop over the active and unused entries. * Stop when we reach the leaf/tail portion of the block. */ while (ptr < endptr) { /* * If it's unused, just skip over it. */ dup = (xfs_dir2_data_unused_t *)ptr; if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) { ptr += be16_to_cpu(dup->length); continue; } dep = (xfs_dir2_data_entry_t *)ptr; /* * Skip . */ if (dep->namelen == 1 && dep->name[0] == '.') ASSERT(be64_to_cpu(dep->inumber) == dp->i_ino); /* * Skip .., but make sure the inode number is right. */ else if (dep->namelen == 2 && dep->name[0] == '.' && dep->name[1] == '.') ASSERT(be64_to_cpu(dep->inumber) == dp->d_ops->sf_get_parent_ino(sfp)); /* * Normal entry, copy it into shortform. */ else { sfep->namelen = dep->namelen; xfs_dir2_sf_put_offset(sfep, (xfs_dir2_data_aoff_t) ((char *)dep - (char *)hdr)); memcpy(sfep->name, dep->name, dep->namelen); dp->d_ops->sf_put_ino(sfp, sfep, be64_to_cpu(dep->inumber)); dp->d_ops->sf_put_ftype(sfep, dp->d_ops->data_get_ftype(dep)); sfep = dp->d_ops->sf_nextentry(sfp, sfep); } ptr += dp->d_ops->data_entsize(dep->namelen); } ASSERT((char *)sfep - (char *)sfp == size); /* now we are done with the block, we can shrink the inode */ logflags = XFS_ILOG_CORE; error = xfs_dir2_shrink_inode(args, args->geo->datablk, bp); if (error) { ASSERT(error != -ENOSPC); goto out; } /* * The buffer is now unconditionally gone, whether * xfs_dir2_shrink_inode worked or not. * * Convert the inode to local format and copy the data in. */ dp->i_df.if_flags &= ~XFS_IFEXTENTS; dp->i_df.if_flags |= XFS_IFINLINE; dp->i_d.di_format = XFS_DINODE_FMT_LOCAL; ASSERT(dp->i_df.if_bytes == 0); xfs_idata_realloc(dp, size, XFS_DATA_FORK); logflags |= XFS_ILOG_DDATA; memcpy(dp->i_df.if_u1.if_data, dst, size); dp->i_d.di_size = size; xfs_dir2_sf_check(args); out: xfs_trans_log_inode(args->trans, dp, logflags); kmem_free(dst); return error; } /* * Add a name to a shortform directory. * There are two algorithms, "easy" and "hard" which we decide on * before changing anything. * Convert to block form if necessary, if the new entry won't fit. */ int /* error */ xfs_dir2_sf_addname( xfs_da_args_t *args) /* operation arguments */ { xfs_inode_t *dp; /* incore directory inode */ int error; /* error return value */ int incr_isize; /* total change in size */ int new_isize; /* di_size after adding name */ int objchange; /* changing to 8-byte inodes */ xfs_dir2_data_aoff_t offset = 0; /* offset for new entry */ int pick; /* which algorithm to use */ xfs_dir2_sf_hdr_t *sfp; /* shortform structure */ xfs_dir2_sf_entry_t *sfep = NULL; /* shortform entry */ trace_xfs_dir2_sf_addname(args); ASSERT(xfs_dir2_sf_lookup(args) == -ENOENT); dp = args->dp; ASSERT(dp->i_df.if_flags & XFS_IFINLINE); /* * Make sure the shortform value has some of its header. */ if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) { ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount)); return -EIO; } ASSERT(dp->i_df.if_bytes == dp->i_d.di_size); ASSERT(dp->i_df.if_u1.if_data != NULL); sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; ASSERT(dp->i_d.di_size >= xfs_dir2_sf_hdr_size(sfp->i8count)); /* * Compute entry (and change in) size. */ incr_isize = dp->d_ops->sf_entsize(sfp, args->namelen); objchange = 0; /* * Do we have to change to 8 byte inodes? */ if (args->inumber > XFS_DIR2_MAX_SHORT_INUM && sfp->i8count == 0) { /* * Yes, adjust the inode size. old count + (parent + new) */ incr_isize += (sfp->count + 2) * ((uint)sizeof(xfs_dir2_ino8_t) - (uint)sizeof(xfs_dir2_ino4_t)); objchange = 1; } new_isize = (int)dp->i_d.di_size + incr_isize; /* * Won't fit as shortform any more (due to size), * or the pick routine says it won't (due to offset values). */ if (new_isize > XFS_IFORK_DSIZE(dp) || (pick = xfs_dir2_sf_addname_pick(args, objchange, &sfep, &offset)) == 0) { /* * Just checking or no space reservation, it doesn't fit. */ if ((args->op_flags & XFS_DA_OP_JUSTCHECK) || args->total == 0) return -ENOSPC; /* * Convert to block form then add the name. */ error = xfs_dir2_sf_to_block(args); if (error) return error; return xfs_dir2_block_addname(args); } /* * Just checking, it fits. */ if (args->op_flags & XFS_DA_OP_JUSTCHECK) return 0; /* * Do it the easy way - just add it at the end. */ if (pick == 1) xfs_dir2_sf_addname_easy(args, sfep, offset, new_isize); /* * Do it the hard way - look for a place to insert the new entry. * Convert to 8 byte inode numbers first if necessary. */ else { ASSERT(pick == 2); if (objchange) xfs_dir2_sf_toino8(args); xfs_dir2_sf_addname_hard(args, objchange, new_isize); } xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA); return 0; } /* * Add the new entry the "easy" way. * This is copying the old directory and adding the new entry at the end. * Since it's sorted by "offset" we need room after the last offset * that's already there, and then room to convert to a block directory. * This is already checked by the pick routine. */ static void xfs_dir2_sf_addname_easy( xfs_da_args_t *args, /* operation arguments */ xfs_dir2_sf_entry_t *sfep, /* pointer to new entry */ xfs_dir2_data_aoff_t offset, /* offset to use for new ent */ int new_isize) /* new directory size */ { int byteoff; /* byte offset in sf dir */ xfs_inode_t *dp; /* incore directory inode */ xfs_dir2_sf_hdr_t *sfp; /* shortform structure */ dp = args->dp; sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; byteoff = (int)((char *)sfep - (char *)sfp); /* * Grow the in-inode space. */ xfs_idata_realloc(dp, dp->d_ops->sf_entsize(sfp, args->namelen), XFS_DATA_FORK); /* * Need to set up again due to realloc of the inode data. */ sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; sfep = (xfs_dir2_sf_entry_t *)((char *)sfp + byteoff); /* * Fill in the new entry. */ sfep->namelen = args->namelen; xfs_dir2_sf_put_offset(sfep, offset); memcpy(sfep->name, args->name, sfep->namelen); dp->d_ops->sf_put_ino(sfp, sfep, args->inumber); dp->d_ops->sf_put_ftype(sfep, args->filetype); /* * Update the header and inode. */ sfp->count++; if (args->inumber > XFS_DIR2_MAX_SHORT_INUM) sfp->i8count++; dp->i_d.di_size = new_isize; xfs_dir2_sf_check(args); } /* * Add the new entry the "hard" way. * The caller has already converted to 8 byte inode numbers if necessary, * in which case we need to leave the i8count at 1. * Find a hole that the new entry will fit into, and copy * the first part of the entries, the new entry, and the last part of * the entries. */ /* ARGSUSED */ static void xfs_dir2_sf_addname_hard( xfs_da_args_t *args, /* operation arguments */ int objchange, /* changing inode number size */ int new_isize) /* new directory size */ { int add_datasize; /* data size need for new ent */ char *buf; /* buffer for old */ xfs_inode_t *dp; /* incore directory inode */ int eof; /* reached end of old dir */ int nbytes; /* temp for byte copies */ xfs_dir2_data_aoff_t new_offset; /* next offset value */ xfs_dir2_data_aoff_t offset; /* current offset value */ int old_isize; /* previous di_size */ xfs_dir2_sf_entry_t *oldsfep; /* entry in original dir */ xfs_dir2_sf_hdr_t *oldsfp; /* original shortform dir */ xfs_dir2_sf_entry_t *sfep; /* entry in new dir */ xfs_dir2_sf_hdr_t *sfp; /* new shortform dir */ /* * Copy the old directory to the stack buffer. */ dp = args->dp; sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; old_isize = (int)dp->i_d.di_size; buf = kmem_alloc(old_isize, KM_SLEEP); oldsfp = (xfs_dir2_sf_hdr_t *)buf; memcpy(oldsfp, sfp, old_isize); /* * Loop over the old directory finding the place we're going * to insert the new entry. * If it's going to end up at the end then oldsfep will point there. */ for (offset = dp->d_ops->data_first_offset, oldsfep = xfs_dir2_sf_firstentry(oldsfp), add_datasize = dp->d_ops->data_entsize(args->namelen), eof = (char *)oldsfep == &buf[old_isize]; !eof; offset = new_offset + dp->d_ops->data_entsize(oldsfep->namelen), oldsfep = dp->d_ops->sf_nextentry(oldsfp, oldsfep), eof = (char *)oldsfep == &buf[old_isize]) { new_offset = xfs_dir2_sf_get_offset(oldsfep); if (offset + add_datasize <= new_offset) break; } /* * Get rid of the old directory, then allocate space for * the new one. We do this so xfs_idata_realloc won't copy * the data. */ xfs_idata_realloc(dp, -old_isize, XFS_DATA_FORK); xfs_idata_realloc(dp, new_isize, XFS_DATA_FORK); /* * Reset the pointer since the buffer was reallocated. */ sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; /* * Copy the first part of the directory, including the header. */ nbytes = (int)((char *)oldsfep - (char *)oldsfp); memcpy(sfp, oldsfp, nbytes); sfep = (xfs_dir2_sf_entry_t *)((char *)sfp + nbytes); /* * Fill in the new entry, and update the header counts. */ sfep->namelen = args->namelen; xfs_dir2_sf_put_offset(sfep, offset); memcpy(sfep->name, args->name, sfep->namelen); dp->d_ops->sf_put_ino(sfp, sfep, args->inumber); dp->d_ops->sf_put_ftype(sfep, args->filetype); sfp->count++; if (args->inumber > XFS_DIR2_MAX_SHORT_INUM && !objchange) sfp->i8count++; /* * If there's more left to copy, do that. */ if (!eof) { sfep = dp->d_ops->sf_nextentry(sfp, sfep); memcpy(sfep, oldsfep, old_isize - nbytes); } kmem_free(buf); dp->i_d.di_size = new_isize; xfs_dir2_sf_check(args); } /* * Decide if the new entry will fit at all. * If it will fit, pick between adding the new entry to the end (easy) * or somewhere else (hard). * Return 0 (won't fit), 1 (easy), 2 (hard). */ /*ARGSUSED*/ static int /* pick result */ xfs_dir2_sf_addname_pick( xfs_da_args_t *args, /* operation arguments */ int objchange, /* inode # size changes */ xfs_dir2_sf_entry_t **sfepp, /* out(1): new entry ptr */ xfs_dir2_data_aoff_t *offsetp) /* out(1): new offset */ { xfs_inode_t *dp; /* incore directory inode */ int holefit; /* found hole it will fit in */ int i; /* entry number */ xfs_dir2_data_aoff_t offset; /* data block offset */ xfs_dir2_sf_entry_t *sfep; /* shortform entry */ xfs_dir2_sf_hdr_t *sfp; /* shortform structure */ int size; /* entry's data size */ int used; /* data bytes used */ dp = args->dp; sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; size = dp->d_ops->data_entsize(args->namelen); offset = dp->d_ops->data_first_offset; sfep = xfs_dir2_sf_firstentry(sfp); holefit = 0; /* * Loop over sf entries. * Keep track of data offset and whether we've seen a place * to insert the new entry. */ for (i = 0; i < sfp->count; i++) { if (!holefit) holefit = offset + size <= xfs_dir2_sf_get_offset(sfep); offset = xfs_dir2_sf_get_offset(sfep) + dp->d_ops->data_entsize(sfep->namelen); sfep = dp->d_ops->sf_nextentry(sfp, sfep); } /* * Calculate data bytes used excluding the new entry, if this * was a data block (block form directory). */ used = offset + (sfp->count + 3) * (uint)sizeof(xfs_dir2_leaf_entry_t) + (uint)sizeof(xfs_dir2_block_tail_t); /* * If it won't fit in a block form then we can't insert it, * we'll go back, convert to block, then try the insert and convert * to leaf. */ if (used + (holefit ? 0 : size) > args->geo->blksize) return 0; /* * If changing the inode number size, do it the hard way. */ if (objchange) return 2; /* * If it won't fit at the end then do it the hard way (use the hole). */ if (used + size > args->geo->blksize) return 2; /* * Do it the easy way. */ *sfepp = sfep; *offsetp = offset; return 1; } #ifdef DEBUG /* * Check consistency of shortform directory, assert if bad. */ static void xfs_dir2_sf_check( xfs_da_args_t *args) /* operation arguments */ { xfs_inode_t *dp; /* incore directory inode */ int i; /* entry number */ int i8count; /* number of big inode#s */ xfs_ino_t ino; /* entry inode number */ int offset; /* data offset */ xfs_dir2_sf_entry_t *sfep; /* shortform dir entry */ xfs_dir2_sf_hdr_t *sfp; /* shortform structure */ dp = args->dp; sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; offset = dp->d_ops->data_first_offset; ino = dp->d_ops->sf_get_parent_ino(sfp); i8count = ino > XFS_DIR2_MAX_SHORT_INUM; for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->count; i++, sfep = dp->d_ops->sf_nextentry(sfp, sfep)) { ASSERT(xfs_dir2_sf_get_offset(sfep) >= offset); ino = dp->d_ops->sf_get_ino(sfp, sfep); i8count += ino > XFS_DIR2_MAX_SHORT_INUM; offset = xfs_dir2_sf_get_offset(sfep) + dp->d_ops->data_entsize(sfep->namelen); ASSERT(dp->d_ops->sf_get_ftype(sfep) < XFS_DIR3_FT_MAX); } ASSERT(i8count == sfp->i8count); ASSERT((char *)sfep - (char *)sfp == dp->i_d.di_size); ASSERT(offset + (sfp->count + 2) * (uint)sizeof(xfs_dir2_leaf_entry_t) + (uint)sizeof(xfs_dir2_block_tail_t) <= args->geo->blksize); } #endif /* DEBUG */ /* * Create a new (shortform) directory. */ int /* error, always 0 */ xfs_dir2_sf_create( xfs_da_args_t *args, /* operation arguments */ xfs_ino_t pino) /* parent inode number */ { xfs_inode_t *dp; /* incore directory inode */ int i8count; /* parent inode is an 8-byte number */ xfs_dir2_sf_hdr_t *sfp; /* shortform structure */ int size; /* directory size */ trace_xfs_dir2_sf_create(args); dp = args->dp; ASSERT(dp != NULL); ASSERT(dp->i_d.di_size == 0); /* * If it's currently a zero-length extent file, * convert it to local format. */ if (dp->i_d.di_format == XFS_DINODE_FMT_EXTENTS) { dp->i_df.if_flags &= ~XFS_IFEXTENTS; /* just in case */ dp->i_d.di_format = XFS_DINODE_FMT_LOCAL; xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE); dp->i_df.if_flags |= XFS_IFINLINE; } ASSERT(dp->i_df.if_flags & XFS_IFINLINE); ASSERT(dp->i_df.if_bytes == 0); i8count = pino > XFS_DIR2_MAX_SHORT_INUM; size = xfs_dir2_sf_hdr_size(i8count); /* * Make a buffer for the data. */ xfs_idata_realloc(dp, size, XFS_DATA_FORK); /* * Fill in the header, */ sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; sfp->i8count = i8count; /* * Now can put in the inode number, since i8count is set. */ dp->d_ops->sf_put_parent_ino(sfp, pino); sfp->count = 0; dp->i_d.di_size = size; xfs_dir2_sf_check(args); xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA); return 0; } /* * Lookup an entry in a shortform directory. * Returns EEXIST if found, ENOENT if not found. */ int /* error */ xfs_dir2_sf_lookup( xfs_da_args_t *args) /* operation arguments */ { xfs_inode_t *dp; /* incore directory inode */ int i; /* entry index */ int error; xfs_dir2_sf_entry_t *sfep; /* shortform directory entry */ xfs_dir2_sf_hdr_t *sfp; /* shortform structure */ enum xfs_dacmp cmp; /* comparison result */ xfs_dir2_sf_entry_t *ci_sfep; /* case-insens. entry */ trace_xfs_dir2_sf_lookup(args); xfs_dir2_sf_check(args); dp = args->dp; ASSERT(dp->i_df.if_flags & XFS_IFINLINE); /* * Bail out if the directory is way too short. */ if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) { ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount)); return -EIO; } ASSERT(dp->i_df.if_bytes == dp->i_d.di_size); ASSERT(dp->i_df.if_u1.if_data != NULL); sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; ASSERT(dp->i_d.di_size >= xfs_dir2_sf_hdr_size(sfp->i8count)); /* * Special case for . */ if (args->namelen == 1 && args->name[0] == '.') { args->inumber = dp->i_ino; args->cmpresult = XFS_CMP_EXACT; args->filetype = XFS_DIR3_FT_DIR; return -EEXIST; } /* * Special case for .. */ if (args->namelen == 2 && args->name[0] == '.' && args->name[1] == '.') { args->inumber = dp->d_ops->sf_get_parent_ino(sfp); args->cmpresult = XFS_CMP_EXACT; args->filetype = XFS_DIR3_FT_DIR; return -EEXIST; } /* * Loop over all the entries trying to match ours. */ ci_sfep = NULL; for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->count; i++, sfep = dp->d_ops->sf_nextentry(sfp, sfep)) { /* * Compare name and if it's an exact match, return the inode * number. If it's the first case-insensitive match, store the * inode number and continue looking for an exact match. */ cmp = dp->i_mount->m_dirnameops->compname(args, sfep->name, sfep->namelen); if (cmp != XFS_CMP_DIFFERENT && cmp != args->cmpresult) { args->cmpresult = cmp; args->inumber = dp->d_ops->sf_get_ino(sfp, sfep); args->filetype = dp->d_ops->sf_get_ftype(sfep); if (cmp == XFS_CMP_EXACT) return -EEXIST; ci_sfep = sfep; } } ASSERT(args->op_flags & XFS_DA_OP_OKNOENT); /* * Here, we can only be doing a lookup (not a rename or replace). * If a case-insensitive match was not found, return -ENOENT. */ if (!ci_sfep) return -ENOENT; /* otherwise process the CI match as required by the caller */ error = xfs_dir_cilookup_result(args, ci_sfep->name, ci_sfep->namelen); return error; } /* * Remove an entry from a shortform directory. */ int /* error */ xfs_dir2_sf_removename( xfs_da_args_t *args) { int byteoff; /* offset of removed entry */ xfs_inode_t *dp; /* incore directory inode */ int entsize; /* this entry's size */ int i; /* shortform entry index */ int newsize; /* new inode size */ int oldsize; /* old inode size */ xfs_dir2_sf_entry_t *sfep; /* shortform directory entry */ xfs_dir2_sf_hdr_t *sfp; /* shortform structure */ trace_xfs_dir2_sf_removename(args); dp = args->dp; ASSERT(dp->i_df.if_flags & XFS_IFINLINE); oldsize = (int)dp->i_d.di_size; /* * Bail out if the directory is way too short. */ if (oldsize < offsetof(xfs_dir2_sf_hdr_t, parent)) { ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount)); return -EIO; } ASSERT(dp->i_df.if_bytes == oldsize); ASSERT(dp->i_df.if_u1.if_data != NULL); sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; ASSERT(oldsize >= xfs_dir2_sf_hdr_size(sfp->i8count)); /* * Loop over the old directory entries. * Find the one we're deleting. */ for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->count; i++, sfep = dp->d_ops->sf_nextentry(sfp, sfep)) { if (xfs_da_compname(args, sfep->name, sfep->namelen) == XFS_CMP_EXACT) { ASSERT(dp->d_ops->sf_get_ino(sfp, sfep) == args->inumber); break; } } /* * Didn't find it. */ if (i == sfp->count) return -ENOENT; /* * Calculate sizes. */ byteoff = (int)((char *)sfep - (char *)sfp); entsize = dp->d_ops->sf_entsize(sfp, args->namelen); newsize = oldsize - entsize; /* * Copy the part if any after the removed entry, sliding it down. */ if (byteoff + entsize < oldsize) memmove((char *)sfp + byteoff, (char *)sfp + byteoff + entsize, oldsize - (byteoff + entsize)); /* * Fix up the header and file size. */ sfp->count--; dp->i_d.di_size = newsize; /* * Reallocate, making it smaller. */ xfs_idata_realloc(dp, newsize - oldsize, XFS_DATA_FORK); sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; /* * Are we changing inode number size? */ if (args->inumber > XFS_DIR2_MAX_SHORT_INUM) { if (sfp->i8count == 1) xfs_dir2_sf_toino4(args); else sfp->i8count--; } xfs_dir2_sf_check(args); xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA); return 0; } /* * Replace the inode number of an entry in a shortform directory. */ int /* error */ xfs_dir2_sf_replace( xfs_da_args_t *args) /* operation arguments */ { xfs_inode_t *dp; /* incore directory inode */ int i; /* entry index */ xfs_ino_t ino=0; /* entry old inode number */ int i8elevated; /* sf_toino8 set i8count=1 */ xfs_dir2_sf_entry_t *sfep; /* shortform directory entry */ xfs_dir2_sf_hdr_t *sfp; /* shortform structure */ trace_xfs_dir2_sf_replace(args); dp = args->dp; ASSERT(dp->i_df.if_flags & XFS_IFINLINE); /* * Bail out if the shortform directory is way too small. */ if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) { ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount)); return -EIO; } ASSERT(dp->i_df.if_bytes == dp->i_d.di_size); ASSERT(dp->i_df.if_u1.if_data != NULL); sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; ASSERT(dp->i_d.di_size >= xfs_dir2_sf_hdr_size(sfp->i8count)); /* * New inode number is large, and need to convert to 8-byte inodes. */ if (args->inumber > XFS_DIR2_MAX_SHORT_INUM && sfp->i8count == 0) { int error; /* error return value */ int newsize; /* new inode size */ newsize = dp->i_df.if_bytes + (sfp->count + 1) * ((uint)sizeof(xfs_dir2_ino8_t) - (uint)sizeof(xfs_dir2_ino4_t)); /* * Won't fit as shortform, convert to block then do replace. */ if (newsize > XFS_IFORK_DSIZE(dp)) { error = xfs_dir2_sf_to_block(args); if (error) { return error; } return xfs_dir2_block_replace(args); } /* * Still fits, convert to 8-byte now. */ xfs_dir2_sf_toino8(args); i8elevated = 1; sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; } else i8elevated = 0; ASSERT(args->namelen != 1 || args->name[0] != '.'); /* * Replace ..'s entry. */ if (args->namelen == 2 && args->name[0] == '.' && args->name[1] == '.') { ino = dp->d_ops->sf_get_parent_ino(sfp); ASSERT(args->inumber != ino); dp->d_ops->sf_put_parent_ino(sfp, args->inumber); } /* * Normal entry, look for the name. */ else { for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->count; i++, sfep = dp->d_ops->sf_nextentry(sfp, sfep)) { if (xfs_da_compname(args, sfep->name, sfep->namelen) == XFS_CMP_EXACT) { ino = dp->d_ops->sf_get_ino(sfp, sfep); ASSERT(args->inumber != ino); dp->d_ops->sf_put_ino(sfp, sfep, args->inumber); dp->d_ops->sf_put_ftype(sfep, args->filetype); break; } } /* * Didn't find it. */ if (i == sfp->count) { ASSERT(args->op_flags & XFS_DA_OP_OKNOENT); if (i8elevated) xfs_dir2_sf_toino4(args); return -ENOENT; } } /* * See if the old number was large, the new number is small. */ if (ino > XFS_DIR2_MAX_SHORT_INUM && args->inumber <= XFS_DIR2_MAX_SHORT_INUM) { /* * And the old count was one, so need to convert to small. */ if (sfp->i8count == 1) xfs_dir2_sf_toino4(args); else sfp->i8count--; } /* * See if the old number was small, the new number is large. */ if (ino <= XFS_DIR2_MAX_SHORT_INUM && args->inumber > XFS_DIR2_MAX_SHORT_INUM) { /* * add to the i8count unless we just converted to 8-byte * inodes (which does an implied i8count = 1) */ ASSERT(sfp->i8count != 0); if (!i8elevated) sfp->i8count++; } xfs_dir2_sf_check(args); xfs_trans_log_inode(args->trans, dp, XFS_ILOG_DDATA); return 0; } /* * Convert from 8-byte inode numbers to 4-byte inode numbers. * The last 8-byte inode number is gone, but the count is still 1. */ static void xfs_dir2_sf_toino4( xfs_da_args_t *args) /* operation arguments */ { char *buf; /* old dir's buffer */ xfs_inode_t *dp; /* incore directory inode */ int i; /* entry index */ int newsize; /* new inode size */ xfs_dir2_sf_entry_t *oldsfep; /* old sf entry */ xfs_dir2_sf_hdr_t *oldsfp; /* old sf directory */ int oldsize; /* old inode size */ xfs_dir2_sf_entry_t *sfep; /* new sf entry */ xfs_dir2_sf_hdr_t *sfp; /* new sf directory */ trace_xfs_dir2_sf_toino4(args); dp = args->dp; /* * Copy the old directory to the buffer. * Then nuke it from the inode, and add the new buffer to the inode. * Don't want xfs_idata_realloc copying the data here. */ oldsize = dp->i_df.if_bytes; buf = kmem_alloc(oldsize, KM_SLEEP); oldsfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; ASSERT(oldsfp->i8count == 1); memcpy(buf, oldsfp, oldsize); /* * Compute the new inode size. */ newsize = oldsize - (oldsfp->count + 1) * ((uint)sizeof(xfs_dir2_ino8_t) - (uint)sizeof(xfs_dir2_ino4_t)); xfs_idata_realloc(dp, -oldsize, XFS_DATA_FORK); xfs_idata_realloc(dp, newsize, XFS_DATA_FORK); /* * Reset our pointers, the data has moved. */ oldsfp = (xfs_dir2_sf_hdr_t *)buf; sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; /* * Fill in the new header. */ sfp->count = oldsfp->count; sfp->i8count = 0; dp->d_ops->sf_put_parent_ino(sfp, dp->d_ops->sf_get_parent_ino(oldsfp)); /* * Copy the entries field by field. */ for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp), oldsfep = xfs_dir2_sf_firstentry(oldsfp); i < sfp->count; i++, sfep = dp->d_ops->sf_nextentry(sfp, sfep), oldsfep = dp->d_ops->sf_nextentry(oldsfp, oldsfep)) { sfep->namelen = oldsfep->namelen; sfep->offset = oldsfep->offset; memcpy(sfep->name, oldsfep->name, sfep->namelen); dp->d_ops->sf_put_ino(sfp, sfep, dp->d_ops->sf_get_ino(oldsfp, oldsfep)); dp->d_ops->sf_put_ftype(sfep, dp->d_ops->sf_get_ftype(oldsfep)); } /* * Clean up the inode. */ kmem_free(buf); dp->i_d.di_size = newsize; xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA); } /* * Convert existing entries from 4-byte inode numbers to 8-byte inode numbers. * The new entry w/ an 8-byte inode number is not there yet; we leave with * i8count set to 1, but no corresponding 8-byte entry. */ static void xfs_dir2_sf_toino8( xfs_da_args_t *args) /* operation arguments */ { char *buf; /* old dir's buffer */ xfs_inode_t *dp; /* incore directory inode */ int i; /* entry index */ int newsize; /* new inode size */ xfs_dir2_sf_entry_t *oldsfep; /* old sf entry */ xfs_dir2_sf_hdr_t *oldsfp; /* old sf directory */ int oldsize; /* old inode size */ xfs_dir2_sf_entry_t *sfep; /* new sf entry */ xfs_dir2_sf_hdr_t *sfp; /* new sf directory */ trace_xfs_dir2_sf_toino8(args); dp = args->dp; /* * Copy the old directory to the buffer. * Then nuke it from the inode, and add the new buffer to the inode. * Don't want xfs_idata_realloc copying the data here. */ oldsize = dp->i_df.if_bytes; buf = kmem_alloc(oldsize, KM_SLEEP); oldsfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; ASSERT(oldsfp->i8count == 0); memcpy(buf, oldsfp, oldsize); /* * Compute the new inode size (nb: entry count + 1 for parent) */ newsize = oldsize + (oldsfp->count + 1) * ((uint)sizeof(xfs_dir2_ino8_t) - (uint)sizeof(xfs_dir2_ino4_t)); xfs_idata_realloc(dp, -oldsize, XFS_DATA_FORK); xfs_idata_realloc(dp, newsize, XFS_DATA_FORK); /* * Reset our pointers, the data has moved. */ oldsfp = (xfs_dir2_sf_hdr_t *)buf; sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; /* * Fill in the new header. */ sfp->count = oldsfp->count; sfp->i8count = 1; dp->d_ops->sf_put_parent_ino(sfp, dp->d_ops->sf_get_parent_ino(oldsfp)); /* * Copy the entries field by field. */ for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp), oldsfep = xfs_dir2_sf_firstentry(oldsfp); i < sfp->count; i++, sfep = dp->d_ops->sf_nextentry(sfp, sfep), oldsfep = dp->d_ops->sf_nextentry(oldsfp, oldsfep)) { sfep->namelen = oldsfep->namelen; sfep->offset = oldsfep->offset; memcpy(sfep->name, oldsfep->name, sfep->namelen); dp->d_ops->sf_put_ino(sfp, sfep, dp->d_ops->sf_get_ino(oldsfp, oldsfep)); dp->d_ops->sf_put_ftype(sfep, dp->d_ops->sf_get_ftype(oldsfep)); } /* * Clean up the inode. */ kmem_free(buf); dp->i_d.di_size = newsize; xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA); } partclone-0.2.86/src/xfs/xfs_dquot_buf.c000066400000000000000000000174221262102574200202100ustar00rootroot00000000000000/* * Copyright (c) 2000-2006 Silicon Graphics, Inc. * Copyright (c) 2013 Red Hat, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_mount.h" #include "xfs_inode.h" #include "xfs_trans.h" #include "xfs_cksum.h" #include "xfs_trace.h" #include "xfs_quota_defs.h" /* * XXX: kernel implementation causes ndquots calc to go real * bad. Just leaving the existing userspace calc here right now. */ int xfs_calc_dquots_per_chunk( unsigned int nbblks) /* basic block units */ { ASSERT(nbblks > 0); return BBTOB(nbblks) / sizeof(xfs_dqblk_t); #if 0 /* kernel code that goes wrong in userspace! */ unsigned int ndquots; ASSERT(nbblks > 0); ndquots = BBTOB(nbblks); do_div(ndquots, sizeof(xfs_dqblk_t)); return ndquots; #endif } /* * Do some primitive error checking on ondisk dquot data structures. */ int xfs_dqcheck( struct xfs_mount *mp, xfs_disk_dquot_t *ddq, xfs_dqid_t id, uint type, /* used only when IO_dorepair is true */ uint flags, char *str) { xfs_dqblk_t *d = (xfs_dqblk_t *)ddq; int errs = 0; /* * We can encounter an uninitialized dquot buffer for 2 reasons: * 1. If we crash while deleting the quotainode(s), and those blks got * used for user data. This is because we take the path of regular * file deletion; however, the size field of quotainodes is never * updated, so all the tricks that we play in itruncate_finish * don't quite matter. * * 2. We don't play the quota buffers when there's a quotaoff logitem. * But the allocation will be replayed so we'll end up with an * uninitialized quota block. * * This is all fine; things are still consistent, and we haven't lost * any quota information. Just don't complain about bad dquot blks. */ if (ddq->d_magic != cpu_to_be16(XFS_DQUOT_MAGIC)) { if (flags & XFS_QMOPT_DOWARN) xfs_alert(mp, "%s : XFS dquot ID 0x%x, magic 0x%x != 0x%x", str, id, be16_to_cpu(ddq->d_magic), XFS_DQUOT_MAGIC); errs++; } if (ddq->d_version != XFS_DQUOT_VERSION) { if (flags & XFS_QMOPT_DOWARN) xfs_alert(mp, "%s : XFS dquot ID 0x%x, version 0x%x != 0x%x", str, id, ddq->d_version, XFS_DQUOT_VERSION); errs++; } if (ddq->d_flags != XFS_DQ_USER && ddq->d_flags != XFS_DQ_PROJ && ddq->d_flags != XFS_DQ_GROUP) { if (flags & XFS_QMOPT_DOWARN) xfs_alert(mp, "%s : XFS dquot ID 0x%x, unknown flags 0x%x", str, id, ddq->d_flags); errs++; } if (id != -1 && id != be32_to_cpu(ddq->d_id)) { if (flags & XFS_QMOPT_DOWARN) xfs_alert(mp, "%s : ondisk-dquot 0x%p, ID mismatch: " "0x%x expected, found id 0x%x", str, ddq, id, be32_to_cpu(ddq->d_id)); errs++; } if (!errs && ddq->d_id) { if (ddq->d_blk_softlimit && be64_to_cpu(ddq->d_bcount) > be64_to_cpu(ddq->d_blk_softlimit)) { if (!ddq->d_btimer) { if (flags & XFS_QMOPT_DOWARN) xfs_alert(mp, "%s : Dquot ID 0x%x (0x%p) BLK TIMER NOT STARTED", str, (int)be32_to_cpu(ddq->d_id), ddq); errs++; } } if (ddq->d_ino_softlimit && be64_to_cpu(ddq->d_icount) > be64_to_cpu(ddq->d_ino_softlimit)) { if (!ddq->d_itimer) { if (flags & XFS_QMOPT_DOWARN) xfs_alert(mp, "%s : Dquot ID 0x%x (0x%p) INODE TIMER NOT STARTED", str, (int)be32_to_cpu(ddq->d_id), ddq); errs++; } } if (ddq->d_rtb_softlimit && be64_to_cpu(ddq->d_rtbcount) > be64_to_cpu(ddq->d_rtb_softlimit)) { if (!ddq->d_rtbtimer) { if (flags & XFS_QMOPT_DOWARN) xfs_alert(mp, "%s : Dquot ID 0x%x (0x%p) RTBLK TIMER NOT STARTED", str, (int)be32_to_cpu(ddq->d_id), ddq); errs++; } } } if (!errs || !(flags & XFS_QMOPT_DQREPAIR)) return errs; if (flags & XFS_QMOPT_DOWARN) xfs_notice(mp, "Re-initializing dquot ID 0x%x", id); /* * Typically, a repair is only requested by quotacheck. */ ASSERT(id != -1); ASSERT(flags & XFS_QMOPT_DQREPAIR); memset(d, 0, sizeof(xfs_dqblk_t)); d->dd_diskdq.d_magic = cpu_to_be16(XFS_DQUOT_MAGIC); d->dd_diskdq.d_version = XFS_DQUOT_VERSION; d->dd_diskdq.d_flags = type; d->dd_diskdq.d_id = cpu_to_be32(id); if (xfs_sb_version_hascrc(&mp->m_sb)) { uuid_copy(&d->dd_uuid, &mp->m_sb.sb_meta_uuid); xfs_update_cksum((char *)d, sizeof(struct xfs_dqblk), XFS_DQUOT_CRC_OFF); } return errs; } STATIC bool xfs_dquot_buf_verify_crc( struct xfs_mount *mp, struct xfs_buf *bp) { struct xfs_dqblk *d = (struct xfs_dqblk *)bp->b_addr; int ndquots; int i; if (!xfs_sb_version_hascrc(&mp->m_sb)) return true; /* * if we are in log recovery, the quota subsystem has not been * initialised so we have no quotainfo structure. In that case, we need * to manually calculate the number of dquots in the buffer. */ if (mp->m_quotainfo) ndquots = mp->m_quotainfo->qi_dqperchunk; else ndquots = xfs_calc_dquots_per_chunk(bp->b_length); // XFS_BB_TO_FSB(mp, bp->b_length)); for (i = 0; i < ndquots; i++, d++) { if (!xfs_verify_cksum((char *)d, sizeof(struct xfs_dqblk), XFS_DQUOT_CRC_OFF)) return false; if (!uuid_equal(&d->dd_uuid, &mp->m_sb.sb_meta_uuid)) return false; } return true; } STATIC bool xfs_dquot_buf_verify( struct xfs_mount *mp, struct xfs_buf *bp) { struct xfs_dqblk *d = (struct xfs_dqblk *)bp->b_addr; xfs_dqid_t id = 0; int ndquots; int i; /* * if we are in log recovery, the quota subsystem has not been * initialised so we have no quotainfo structure. In that case, we need * to manually calculate the number of dquots in the buffer. */ if (mp->m_quotainfo) ndquots = mp->m_quotainfo->qi_dqperchunk; else ndquots = xfs_calc_dquots_per_chunk(bp->b_length); /* * On the first read of the buffer, verify that each dquot is valid. * We don't know what the id of the dquot is supposed to be, just that * they should be increasing monotonically within the buffer. If the * first id is corrupt, then it will fail on the second dquot in the * buffer so corruptions could point to the wrong dquot in this case. */ for (i = 0; i < ndquots; i++) { struct xfs_disk_dquot *ddq; int error; ddq = &d[i].dd_diskdq; if (i == 0) id = be32_to_cpu(ddq->d_id); error = xfs_dqcheck(mp, ddq, id + i, 0, XFS_QMOPT_DOWARN, "xfs_dquot_buf_verify"); if (error) return false; } return true; } static void xfs_dquot_buf_read_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_target->bt_mount; if (!xfs_dquot_buf_verify_crc(mp, bp)) xfs_buf_ioerror(bp, -EFSBADCRC); else if (!xfs_dquot_buf_verify(mp, bp)) xfs_buf_ioerror(bp, -EFSCORRUPTED); if (bp->b_error) xfs_verifier_error(bp); } /* * we don't calculate the CRC here as that is done when the dquot is flushed to * the buffer after the update is done. This ensures that the dquot in the * buffer always has an up-to-date CRC value. */ static void xfs_dquot_buf_write_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_target->bt_mount; if (!xfs_dquot_buf_verify(mp, bp)) { xfs_buf_ioerror(bp, -EFSCORRUPTED); xfs_verifier_error(bp); return; } } const struct xfs_buf_ops xfs_dquot_buf_ops = { .verify_read = xfs_dquot_buf_read_verify, .verify_write = xfs_dquot_buf_write_verify, }; partclone-0.2.86/src/xfs/xfs_format.h000066400000000000000000001433171262102574200175200ustar00rootroot00000000000000/* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __XFS_FORMAT_H__ #define __XFS_FORMAT_H__ /* * XFS On Disk Format Definitions * * This header file defines all the on-disk format definitions for * general XFS objects. Directory and attribute related objects are defined in * xfs_da_format.h, which log and log item formats are defined in * xfs_log_format.h. Everything else goes here. */ struct xfs_mount; struct xfs_trans; struct xfs_inode; struct xfs_buf; struct xfs_ifork; /* * Super block * Fits into a sector-sized buffer at address 0 of each allocation group. * Only the first of these is ever updated except during growfs. */ #define XFS_SB_MAGIC 0x58465342 /* 'XFSB' */ #define XFS_SB_VERSION_1 1 /* 5.3, 6.0.1, 6.1 */ #define XFS_SB_VERSION_2 2 /* 6.2 - attributes */ #define XFS_SB_VERSION_3 3 /* 6.2 - new inode version */ #define XFS_SB_VERSION_4 4 /* 6.2+ - bitmask version */ #define XFS_SB_VERSION_5 5 /* CRC enabled filesystem */ #define XFS_SB_VERSION_NUMBITS 0x000f #define XFS_SB_VERSION_ALLFBITS 0xfff0 #define XFS_SB_VERSION_ATTRBIT 0x0010 #define XFS_SB_VERSION_NLINKBIT 0x0020 #define XFS_SB_VERSION_QUOTABIT 0x0040 #define XFS_SB_VERSION_ALIGNBIT 0x0080 #define XFS_SB_VERSION_DALIGNBIT 0x0100 #define XFS_SB_VERSION_SHAREDBIT 0x0200 #define XFS_SB_VERSION_LOGV2BIT 0x0400 #define XFS_SB_VERSION_SECTORBIT 0x0800 #define XFS_SB_VERSION_EXTFLGBIT 0x1000 #define XFS_SB_VERSION_DIRV2BIT 0x2000 #define XFS_SB_VERSION_BORGBIT 0x4000 /* ASCII only case-insens. */ #define XFS_SB_VERSION_MOREBITSBIT 0x8000 /* * Supported feature bit list is just all bits in the versionnum field because * we've used them all up and understand them all. Except, of course, for the * shared superblock bit, which nobody knows what it does and so is unsupported. */ #define XFS_SB_VERSION_OKBITS \ ((XFS_SB_VERSION_NUMBITS | XFS_SB_VERSION_ALLFBITS) & \ ~XFS_SB_VERSION_SHAREDBIT) /* * There are two words to hold XFS "feature" bits: the original * word, sb_versionnum, and sb_features2. Whenever a bit is set in * sb_features2, the feature bit XFS_SB_VERSION_MOREBITSBIT must be set. * * These defines represent bits in sb_features2. */ #define XFS_SB_VERSION2_RESERVED1BIT 0x00000001 #define XFS_SB_VERSION2_LAZYSBCOUNTBIT 0x00000002 /* Superblk counters */ #define XFS_SB_VERSION2_RESERVED4BIT 0x00000004 #define XFS_SB_VERSION2_ATTR2BIT 0x00000008 /* Inline attr rework */ #define XFS_SB_VERSION2_PARENTBIT 0x00000010 /* parent pointers */ #define XFS_SB_VERSION2_PROJID32BIT 0x00000080 /* 32 bit project id */ #define XFS_SB_VERSION2_CRCBIT 0x00000100 /* metadata CRCs */ #define XFS_SB_VERSION2_FTYPE 0x00000200 /* inode type in dir */ #define XFS_SB_VERSION2_OKBITS \ (XFS_SB_VERSION2_LAZYSBCOUNTBIT | \ XFS_SB_VERSION2_ATTR2BIT | \ XFS_SB_VERSION2_PROJID32BIT | \ XFS_SB_VERSION2_FTYPE) /* * Superblock - in core version. Must match the ondisk version below. * Must be padded to 64 bit alignment. */ typedef struct xfs_sb { __uint32_t sb_magicnum; /* magic number == XFS_SB_MAGIC */ __uint32_t sb_blocksize; /* logical block size, bytes */ xfs_rfsblock_t sb_dblocks; /* number of data blocks */ xfs_rfsblock_t sb_rblocks; /* number of realtime blocks */ xfs_rtblock_t sb_rextents; /* number of realtime extents */ uuid_t sb_uuid; /* user-visible file system unique id */ xfs_fsblock_t sb_logstart; /* starting block of log if internal */ xfs_ino_t sb_rootino; /* root inode number */ xfs_ino_t sb_rbmino; /* bitmap inode for realtime extents */ xfs_ino_t sb_rsumino; /* summary inode for rt bitmap */ xfs_agblock_t sb_rextsize; /* realtime extent size, blocks */ xfs_agblock_t sb_agblocks; /* size of an allocation group */ xfs_agnumber_t sb_agcount; /* number of allocation groups */ xfs_extlen_t sb_rbmblocks; /* number of rt bitmap blocks */ xfs_extlen_t sb_logblocks; /* number of log blocks */ __uint16_t sb_versionnum; /* header version == XFS_SB_VERSION */ __uint16_t sb_sectsize; /* volume sector size, bytes */ __uint16_t sb_inodesize; /* inode size, bytes */ __uint16_t sb_inopblock; /* inodes per block */ char sb_fname[12]; /* file system name */ __uint8_t sb_blocklog; /* log2 of sb_blocksize */ __uint8_t sb_sectlog; /* log2 of sb_sectsize */ __uint8_t sb_inodelog; /* log2 of sb_inodesize */ __uint8_t sb_inopblog; /* log2 of sb_inopblock */ __uint8_t sb_agblklog; /* log2 of sb_agblocks (rounded up) */ __uint8_t sb_rextslog; /* log2 of sb_rextents */ __uint8_t sb_inprogress; /* mkfs is in progress, don't mount */ __uint8_t sb_imax_pct; /* max % of fs for inode space */ /* statistics */ /* * These fields must remain contiguous. If you really * want to change their layout, make sure you fix the * code in xfs_trans_apply_sb_deltas(). */ __uint64_t sb_icount; /* allocated inodes */ __uint64_t sb_ifree; /* free inodes */ __uint64_t sb_fdblocks; /* free data blocks */ __uint64_t sb_frextents; /* free realtime extents */ /* * End contiguous fields. */ xfs_ino_t sb_uquotino; /* user quota inode */ xfs_ino_t sb_gquotino; /* group quota inode */ __uint16_t sb_qflags; /* quota flags */ __uint8_t sb_flags; /* misc. flags */ __uint8_t sb_shared_vn; /* shared version number */ xfs_extlen_t sb_inoalignmt; /* inode chunk alignment, fsblocks */ __uint32_t sb_unit; /* stripe or raid unit */ __uint32_t sb_width; /* stripe or raid width */ __uint8_t sb_dirblklog; /* log2 of dir block size (fsbs) */ __uint8_t sb_logsectlog; /* log2 of the log sector size */ __uint16_t sb_logsectsize; /* sector size for the log, bytes */ __uint32_t sb_logsunit; /* stripe unit size for the log */ __uint32_t sb_features2; /* additional feature bits */ /* * bad features2 field as a result of failing to pad the sb structure to * 64 bits. Some machines will be using this field for features2 bits. * Easiest just to mark it bad and not use it for anything else. * * This is not kept up to date in memory; it is always overwritten by * the value in sb_features2 when formatting the incore superblock to * the disk buffer. */ __uint32_t sb_bad_features2; /* version 5 superblock fields start here */ /* feature masks */ __uint32_t sb_features_compat; __uint32_t sb_features_ro_compat; __uint32_t sb_features_incompat; __uint32_t sb_features_log_incompat; __uint32_t sb_crc; /* superblock crc */ xfs_extlen_t sb_spino_align; /* sparse inode chunk alignment */ xfs_ino_t sb_pquotino; /* project quota inode */ xfs_lsn_t sb_lsn; /* last write sequence */ uuid_t sb_meta_uuid; /* metadata file system unique id */ /* must be padded to 64 bit alignment */ } xfs_sb_t; #define XFS_SB_CRC_OFF offsetof(struct xfs_sb, sb_crc) /* * Superblock - on disk version. Must match the in core version above. * Must be padded to 64 bit alignment. */ typedef struct xfs_dsb { __be32 sb_magicnum; /* magic number == XFS_SB_MAGIC */ __be32 sb_blocksize; /* logical block size, bytes */ __be64 sb_dblocks; /* number of data blocks */ __be64 sb_rblocks; /* number of realtime blocks */ __be64 sb_rextents; /* number of realtime extents */ uuid_t sb_uuid; /* user-visible file system unique id */ __be64 sb_logstart; /* starting block of log if internal */ __be64 sb_rootino; /* root inode number */ __be64 sb_rbmino; /* bitmap inode for realtime extents */ __be64 sb_rsumino; /* summary inode for rt bitmap */ __be32 sb_rextsize; /* realtime extent size, blocks */ __be32 sb_agblocks; /* size of an allocation group */ __be32 sb_agcount; /* number of allocation groups */ __be32 sb_rbmblocks; /* number of rt bitmap blocks */ __be32 sb_logblocks; /* number of log blocks */ __be16 sb_versionnum; /* header version == XFS_SB_VERSION */ __be16 sb_sectsize; /* volume sector size, bytes */ __be16 sb_inodesize; /* inode size, bytes */ __be16 sb_inopblock; /* inodes per block */ char sb_fname[12]; /* file system name */ __u8 sb_blocklog; /* log2 of sb_blocksize */ __u8 sb_sectlog; /* log2 of sb_sectsize */ __u8 sb_inodelog; /* log2 of sb_inodesize */ __u8 sb_inopblog; /* log2 of sb_inopblock */ __u8 sb_agblklog; /* log2 of sb_agblocks (rounded up) */ __u8 sb_rextslog; /* log2 of sb_rextents */ __u8 sb_inprogress; /* mkfs is in progress, don't mount */ __u8 sb_imax_pct; /* max % of fs for inode space */ /* statistics */ /* * These fields must remain contiguous. If you really * want to change their layout, make sure you fix the * code in xfs_trans_apply_sb_deltas(). */ __be64 sb_icount; /* allocated inodes */ __be64 sb_ifree; /* free inodes */ __be64 sb_fdblocks; /* free data blocks */ __be64 sb_frextents; /* free realtime extents */ /* * End contiguous fields. */ __be64 sb_uquotino; /* user quota inode */ __be64 sb_gquotino; /* group quota inode */ __be16 sb_qflags; /* quota flags */ __u8 sb_flags; /* misc. flags */ __u8 sb_shared_vn; /* shared version number */ __be32 sb_inoalignmt; /* inode chunk alignment, fsblocks */ __be32 sb_unit; /* stripe or raid unit */ __be32 sb_width; /* stripe or raid width */ __u8 sb_dirblklog; /* log2 of dir block size (fsbs) */ __u8 sb_logsectlog; /* log2 of the log sector size */ __be16 sb_logsectsize; /* sector size for the log, bytes */ __be32 sb_logsunit; /* stripe unit size for the log */ __be32 sb_features2; /* additional feature bits */ /* * bad features2 field as a result of failing to pad the sb * structure to 64 bits. Some machines will be using this field * for features2 bits. Easiest just to mark it bad and not use * it for anything else. */ __be32 sb_bad_features2; /* version 5 superblock fields start here */ /* feature masks */ __be32 sb_features_compat; __be32 sb_features_ro_compat; __be32 sb_features_incompat; __be32 sb_features_log_incompat; __le32 sb_crc; /* superblock crc */ __be32 sb_spino_align; /* sparse inode chunk alignment */ __be64 sb_pquotino; /* project quota inode */ __be64 sb_lsn; /* last write sequence */ uuid_t sb_meta_uuid; /* metadata file system unique id */ /* must be padded to 64 bit alignment */ } xfs_dsb_t; /* * Misc. Flags - warning - these will be cleared by xfs_repair unless * a feature bit is set when the flag is used. */ #define XFS_SBF_NOFLAGS 0x00 /* no flags set */ #define XFS_SBF_READONLY 0x01 /* only read-only mounts allowed */ /* * define max. shared version we can interoperate with */ #define XFS_SB_MAX_SHARED_VN 0 #define XFS_SB_VERSION_NUM(sbp) ((sbp)->sb_versionnum & XFS_SB_VERSION_NUMBITS) /* * The first XFS version we support is a v4 superblock with V2 directories. */ static inline bool xfs_sb_good_v4_features(struct xfs_sb *sbp) { if (!(sbp->sb_versionnum & XFS_SB_VERSION_DIRV2BIT)) return false; /* check for unknown features in the fs */ if ((sbp->sb_versionnum & ~XFS_SB_VERSION_OKBITS) || ((sbp->sb_versionnum & XFS_SB_VERSION_MOREBITSBIT) && (sbp->sb_features2 & ~XFS_SB_VERSION2_OKBITS))) return false; return true; } static inline bool xfs_sb_good_version(struct xfs_sb *sbp) { if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) return true; if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) return xfs_sb_good_v4_features(sbp); return false; } /* * Detect a mismatched features2 field. Older kernels read/wrote * this into the wrong slot, so to be safe we keep them in sync. */ static inline bool xfs_sb_has_mismatched_features2(struct xfs_sb *sbp) { return sbp->sb_bad_features2 != sbp->sb_features2; } static inline bool xfs_sb_version_hasattr(struct xfs_sb *sbp) { return (sbp->sb_versionnum & XFS_SB_VERSION_ATTRBIT); } static inline void xfs_sb_version_addattr(struct xfs_sb *sbp) { sbp->sb_versionnum |= XFS_SB_VERSION_ATTRBIT; } static inline bool xfs_sb_version_hasquota(struct xfs_sb *sbp) { return (sbp->sb_versionnum & XFS_SB_VERSION_QUOTABIT); } static inline void xfs_sb_version_addquota(struct xfs_sb *sbp) { sbp->sb_versionnum |= XFS_SB_VERSION_QUOTABIT; } static inline bool xfs_sb_version_hasalign(struct xfs_sb *sbp) { return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5 || (sbp->sb_versionnum & XFS_SB_VERSION_ALIGNBIT)); } static inline bool xfs_sb_version_hasdalign(struct xfs_sb *sbp) { return (sbp->sb_versionnum & XFS_SB_VERSION_DALIGNBIT); } static inline bool xfs_sb_version_haslogv2(struct xfs_sb *sbp) { return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5 || (sbp->sb_versionnum & XFS_SB_VERSION_LOGV2BIT); } static inline bool xfs_sb_version_hasextflgbit(struct xfs_sb *sbp) { return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5 || (sbp->sb_versionnum & XFS_SB_VERSION_EXTFLGBIT); } static inline bool xfs_sb_version_hassector(struct xfs_sb *sbp) { return (sbp->sb_versionnum & XFS_SB_VERSION_SECTORBIT); } static inline bool xfs_sb_version_hasasciici(struct xfs_sb *sbp) { return (sbp->sb_versionnum & XFS_SB_VERSION_BORGBIT); } static inline bool xfs_sb_version_hasmorebits(struct xfs_sb *sbp) { return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5 || (sbp->sb_versionnum & XFS_SB_VERSION_MOREBITSBIT); } /* * sb_features2 bit version macros. */ static inline bool xfs_sb_version_haslazysbcount(struct xfs_sb *sbp) { return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) || (xfs_sb_version_hasmorebits(sbp) && (sbp->sb_features2 & XFS_SB_VERSION2_LAZYSBCOUNTBIT)); } static inline bool xfs_sb_version_hasattr2(struct xfs_sb *sbp) { return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) || (xfs_sb_version_hasmorebits(sbp) && (sbp->sb_features2 & XFS_SB_VERSION2_ATTR2BIT)); } static inline void xfs_sb_version_addattr2(struct xfs_sb *sbp) { sbp->sb_versionnum |= XFS_SB_VERSION_MOREBITSBIT; sbp->sb_features2 |= XFS_SB_VERSION2_ATTR2BIT; } static inline void xfs_sb_version_removeattr2(struct xfs_sb *sbp) { sbp->sb_features2 &= ~XFS_SB_VERSION2_ATTR2BIT; if (!sbp->sb_features2) sbp->sb_versionnum &= ~XFS_SB_VERSION_MOREBITSBIT; } static inline bool xfs_sb_version_hasprojid32bit(struct xfs_sb *sbp) { return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) || (xfs_sb_version_hasmorebits(sbp) && (sbp->sb_features2 & XFS_SB_VERSION2_PROJID32BIT)); } static inline void xfs_sb_version_addprojid32bit(struct xfs_sb *sbp) { sbp->sb_versionnum |= XFS_SB_VERSION_MOREBITSBIT; sbp->sb_features2 |= XFS_SB_VERSION2_PROJID32BIT; } /* * Extended v5 superblock feature masks. These are to be used for new v5 * superblock features only. * * Compat features are new features that old kernels will not notice or affect * and so can mount read-write without issues. * * RO-Compat (read only) are features that old kernels can read but will break * if they write. Hence only read-only mounts of such filesystems are allowed on * kernels that don't support the feature bit. * * InCompat features are features which old kernels will not understand and so * must not mount. * * Log-InCompat features are for changes to log formats or new transactions that * can't be replayed on older kernels. The fields are set when the filesystem is * mounted, and a clean unmount clears the fields. */ #define XFS_SB_FEAT_COMPAT_ALL 0 #define XFS_SB_FEAT_COMPAT_UNKNOWN ~XFS_SB_FEAT_COMPAT_ALL static inline bool xfs_sb_has_compat_feature( struct xfs_sb *sbp, __uint32_t feature) { return (sbp->sb_features_compat & feature) != 0; } #define XFS_SB_FEAT_RO_COMPAT_FINOBT (1 << 0) /* free inode btree */ #define XFS_SB_FEAT_RO_COMPAT_ALL \ (XFS_SB_FEAT_RO_COMPAT_FINOBT) #define XFS_SB_FEAT_RO_COMPAT_UNKNOWN ~XFS_SB_FEAT_RO_COMPAT_ALL static inline bool xfs_sb_has_ro_compat_feature( struct xfs_sb *sbp, __uint32_t feature) { return (sbp->sb_features_ro_compat & feature) != 0; } #define XFS_SB_FEAT_INCOMPAT_FTYPE (1 << 0) /* filetype in dirent */ #define XFS_SB_FEAT_INCOMPAT_SPINODES (1 << 1) /* sparse inode chunks */ #define XFS_SB_FEAT_INCOMPAT_META_UUID (1 << 2) /* metadata UUID */ #define XFS_SB_FEAT_INCOMPAT_ALL \ (XFS_SB_FEAT_INCOMPAT_FTYPE| \ XFS_SB_FEAT_INCOMPAT_SPINODES| \ XFS_SB_FEAT_INCOMPAT_META_UUID) #define XFS_SB_FEAT_INCOMPAT_UNKNOWN ~XFS_SB_FEAT_INCOMPAT_ALL static inline bool xfs_sb_has_incompat_feature( struct xfs_sb *sbp, __uint32_t feature) { return (sbp->sb_features_incompat & feature) != 0; } #define XFS_SB_FEAT_INCOMPAT_LOG_ALL 0 #define XFS_SB_FEAT_INCOMPAT_LOG_UNKNOWN ~XFS_SB_FEAT_INCOMPAT_LOG_ALL static inline bool xfs_sb_has_incompat_log_feature( struct xfs_sb *sbp, __uint32_t feature) { return (sbp->sb_features_log_incompat & feature) != 0; } /* * V5 superblock specific feature checks */ static inline int xfs_sb_version_hascrc(struct xfs_sb *sbp) { return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5; } static inline int xfs_sb_version_has_pquotino(struct xfs_sb *sbp) { return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5; } static inline int xfs_sb_version_hasftype(struct xfs_sb *sbp) { return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5 && xfs_sb_has_incompat_feature(sbp, XFS_SB_FEAT_INCOMPAT_FTYPE)) || (xfs_sb_version_hasmorebits(sbp) && (sbp->sb_features2 & XFS_SB_VERSION2_FTYPE)); } static inline int xfs_sb_version_hasfinobt(xfs_sb_t *sbp) { return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) && (sbp->sb_features_ro_compat & XFS_SB_FEAT_RO_COMPAT_FINOBT); } static inline bool xfs_sb_version_hassparseinodes(struct xfs_sb *sbp) { return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5 && xfs_sb_has_incompat_feature(sbp, XFS_SB_FEAT_INCOMPAT_SPINODES); } /* * XFS_SB_FEAT_INCOMPAT_META_UUID indicates that the metadata UUID * is stored separately from the user-visible UUID; this allows the * user-visible UUID to be changed on V5 filesystems which have a * filesystem UUID stamped into every piece of metadata. */ static inline int xfs_sb_version_hasmetauuid(xfs_sb_t *sbp) { return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) && (sbp->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_META_UUID); } /* * end of superblock version macros */ static inline bool xfs_is_quota_inode(struct xfs_sb *sbp, xfs_ino_t ino) { return (ino == sbp->sb_uquotino || ino == sbp->sb_gquotino || ino == sbp->sb_pquotino); } #define XFS_SB_DADDR ((xfs_daddr_t)0) /* daddr in filesystem/ag */ #define XFS_SB_BLOCK(mp) XFS_HDR_BLOCK(mp, XFS_SB_DADDR) #define XFS_BUF_TO_SBP(bp) ((xfs_dsb_t *)((bp)->b_addr)) #define XFS_HDR_BLOCK(mp,d) ((xfs_agblock_t)XFS_BB_TO_FSBT(mp,d)) #define XFS_DADDR_TO_FSB(mp,d) XFS_AGB_TO_FSB(mp, \ xfs_daddr_to_agno(mp,d), xfs_daddr_to_agbno(mp,d)) #define XFS_FSB_TO_DADDR(mp,fsbno) XFS_AGB_TO_DADDR(mp, \ XFS_FSB_TO_AGNO(mp,fsbno), XFS_FSB_TO_AGBNO(mp,fsbno)) /* * File system sector to basic block conversions. */ #define XFS_FSS_TO_BB(mp,sec) ((sec) << (mp)->m_sectbb_log) /* * File system block to basic block conversions. */ #define XFS_FSB_TO_BB(mp,fsbno) ((fsbno) << (mp)->m_blkbb_log) #define XFS_BB_TO_FSB(mp,bb) \ (((bb) + (XFS_FSB_TO_BB(mp,1) - 1)) >> (mp)->m_blkbb_log) #define XFS_BB_TO_FSBT(mp,bb) ((bb) >> (mp)->m_blkbb_log) /* * File system block to byte conversions. */ #define XFS_FSB_TO_B(mp,fsbno) ((xfs_fsize_t)(fsbno) << (mp)->m_sb.sb_blocklog) #define XFS_B_TO_FSB(mp,b) \ ((((__uint64_t)(b)) + (mp)->m_blockmask) >> (mp)->m_sb.sb_blocklog) #define XFS_B_TO_FSBT(mp,b) (((__uint64_t)(b)) >> (mp)->m_sb.sb_blocklog) #define XFS_B_FSB_OFFSET(mp,b) ((b) & (mp)->m_blockmask) /* * Allocation group header * * This is divided into three structures, placed in sequential 512-byte * buffers after a copy of the superblock (also in a 512-byte buffer). */ #define XFS_AGF_MAGIC 0x58414746 /* 'XAGF' */ #define XFS_AGI_MAGIC 0x58414749 /* 'XAGI' */ #define XFS_AGFL_MAGIC 0x5841464c /* 'XAFL' */ #define XFS_AGF_VERSION 1 #define XFS_AGI_VERSION 1 #define XFS_AGF_GOOD_VERSION(v) ((v) == XFS_AGF_VERSION) #define XFS_AGI_GOOD_VERSION(v) ((v) == XFS_AGI_VERSION) /* * Btree number 0 is bno, 1 is cnt. This value gives the size of the * arrays below. */ #define XFS_BTNUM_AGF ((int)XFS_BTNUM_CNTi + 1) /* * The second word of agf_levels in the first a.g. overlaps the EFS * superblock's magic number. Since the magic numbers valid for EFS * are > 64k, our value cannot be confused for an EFS superblock's. */ typedef struct xfs_agf { /* * Common allocation group header information */ __be32 agf_magicnum; /* magic number == XFS_AGF_MAGIC */ __be32 agf_versionnum; /* header version == XFS_AGF_VERSION */ __be32 agf_seqno; /* sequence # starting from 0 */ __be32 agf_length; /* size in blocks of a.g. */ /* * Freespace information */ __be32 agf_roots[XFS_BTNUM_AGF]; /* root blocks */ __be32 agf_spare0; /* spare field */ __be32 agf_levels[XFS_BTNUM_AGF]; /* btree levels */ __be32 agf_spare1; /* spare field */ __be32 agf_flfirst; /* first freelist block's index */ __be32 agf_fllast; /* last freelist block's index */ __be32 agf_flcount; /* count of blocks in freelist */ __be32 agf_freeblks; /* total free blocks */ __be32 agf_longest; /* longest free space */ __be32 agf_btreeblks; /* # of blocks held in AGF btrees */ uuid_t agf_uuid; /* uuid of filesystem */ /* * reserve some contiguous space for future logged fields before we add * the unlogged fields. This makes the range logging via flags and * structure offsets much simpler. */ __be64 agf_spare64[16]; /* unlogged fields, written during buffer writeback. */ __be64 agf_lsn; /* last write sequence */ __be32 agf_crc; /* crc of agf sector */ __be32 agf_spare2; /* structure must be padded to 64 bit alignment */ } xfs_agf_t; #define XFS_AGF_CRC_OFF offsetof(struct xfs_agf, agf_crc) #define XFS_AGF_MAGICNUM 0x00000001 #define XFS_AGF_VERSIONNUM 0x00000002 #define XFS_AGF_SEQNO 0x00000004 #define XFS_AGF_LENGTH 0x00000008 #define XFS_AGF_ROOTS 0x00000010 #define XFS_AGF_LEVELS 0x00000020 #define XFS_AGF_FLFIRST 0x00000040 #define XFS_AGF_FLLAST 0x00000080 #define XFS_AGF_FLCOUNT 0x00000100 #define XFS_AGF_FREEBLKS 0x00000200 #define XFS_AGF_LONGEST 0x00000400 #define XFS_AGF_BTREEBLKS 0x00000800 #define XFS_AGF_UUID 0x00001000 #define XFS_AGF_NUM_BITS 13 #define XFS_AGF_ALL_BITS ((1 << XFS_AGF_NUM_BITS) - 1) #define XFS_AGF_FLAGS \ { XFS_AGF_MAGICNUM, "MAGICNUM" }, \ { XFS_AGF_VERSIONNUM, "VERSIONNUM" }, \ { XFS_AGF_SEQNO, "SEQNO" }, \ { XFS_AGF_LENGTH, "LENGTH" }, \ { XFS_AGF_ROOTS, "ROOTS" }, \ { XFS_AGF_LEVELS, "LEVELS" }, \ { XFS_AGF_FLFIRST, "FLFIRST" }, \ { XFS_AGF_FLLAST, "FLLAST" }, \ { XFS_AGF_FLCOUNT, "FLCOUNT" }, \ { XFS_AGF_FREEBLKS, "FREEBLKS" }, \ { XFS_AGF_LONGEST, "LONGEST" }, \ { XFS_AGF_BTREEBLKS, "BTREEBLKS" }, \ { XFS_AGF_UUID, "UUID" } /* disk block (xfs_daddr_t) in the AG */ #define XFS_AGF_DADDR(mp) ((xfs_daddr_t)(1 << (mp)->m_sectbb_log)) #define XFS_AGF_BLOCK(mp) XFS_HDR_BLOCK(mp, XFS_AGF_DADDR(mp)) #define XFS_BUF_TO_AGF(bp) ((xfs_agf_t *)((bp)->b_addr)) /* * Size of the unlinked inode hash table in the agi. */ #define XFS_AGI_UNLINKED_BUCKETS 64 typedef struct xfs_agi { /* * Common allocation group header information */ __be32 agi_magicnum; /* magic number == XFS_AGI_MAGIC */ __be32 agi_versionnum; /* header version == XFS_AGI_VERSION */ __be32 agi_seqno; /* sequence # starting from 0 */ __be32 agi_length; /* size in blocks of a.g. */ /* * Inode information * Inodes are mapped by interpreting the inode number, so no * mapping data is needed here. */ __be32 agi_count; /* count of allocated inodes */ __be32 agi_root; /* root of inode btree */ __be32 agi_level; /* levels in inode btree */ __be32 agi_freecount; /* number of free inodes */ __be32 agi_newino; /* new inode just allocated */ __be32 agi_dirino; /* last directory inode chunk */ /* * Hash table of inodes which have been unlinked but are * still being referenced. */ __be32 agi_unlinked[XFS_AGI_UNLINKED_BUCKETS]; /* * This marks the end of logging region 1 and start of logging region 2. */ uuid_t agi_uuid; /* uuid of filesystem */ __be32 agi_crc; /* crc of agi sector */ __be32 agi_pad32; __be64 agi_lsn; /* last write sequence */ __be32 agi_free_root; /* root of the free inode btree */ __be32 agi_free_level;/* levels in free inode btree */ /* structure must be padded to 64 bit alignment */ } xfs_agi_t; #define XFS_AGI_CRC_OFF offsetof(struct xfs_agi, agi_crc) #define XFS_AGI_MAGICNUM (1 << 0) #define XFS_AGI_VERSIONNUM (1 << 1) #define XFS_AGI_SEQNO (1 << 2) #define XFS_AGI_LENGTH (1 << 3) #define XFS_AGI_COUNT (1 << 4) #define XFS_AGI_ROOT (1 << 5) #define XFS_AGI_LEVEL (1 << 6) #define XFS_AGI_FREECOUNT (1 << 7) #define XFS_AGI_NEWINO (1 << 8) #define XFS_AGI_DIRINO (1 << 9) #define XFS_AGI_UNLINKED (1 << 10) #define XFS_AGI_NUM_BITS_R1 11 /* end of the 1st agi logging region */ #define XFS_AGI_ALL_BITS_R1 ((1 << XFS_AGI_NUM_BITS_R1) - 1) #define XFS_AGI_FREE_ROOT (1 << 11) #define XFS_AGI_FREE_LEVEL (1 << 12) #define XFS_AGI_NUM_BITS_R2 13 /* disk block (xfs_daddr_t) in the AG */ #define XFS_AGI_DADDR(mp) ((xfs_daddr_t)(2 << (mp)->m_sectbb_log)) #define XFS_AGI_BLOCK(mp) XFS_HDR_BLOCK(mp, XFS_AGI_DADDR(mp)) #define XFS_BUF_TO_AGI(bp) ((xfs_agi_t *)((bp)->b_addr)) /* * The third a.g. block contains the a.g. freelist, an array * of block pointers to blocks owned by the allocation btree code. */ #define XFS_AGFL_DADDR(mp) ((xfs_daddr_t)(3 << (mp)->m_sectbb_log)) #define XFS_AGFL_BLOCK(mp) XFS_HDR_BLOCK(mp, XFS_AGFL_DADDR(mp)) #define XFS_BUF_TO_AGFL(bp) ((xfs_agfl_t *)((bp)->b_addr)) #define XFS_BUF_TO_AGFL_BNO(mp, bp) \ (xfs_sb_version_hascrc(&((mp)->m_sb)) ? \ &(XFS_BUF_TO_AGFL(bp)->agfl_bno[0]) : \ (__be32 *)(bp)->b_addr) /* * Size of the AGFL. For CRC-enabled filesystes we steal a couple of * slots in the beginning of the block for a proper header with the * location information and CRC. */ #define XFS_AGFL_SIZE(mp) \ (((mp)->m_sb.sb_sectsize - \ (xfs_sb_version_hascrc(&((mp)->m_sb)) ? \ sizeof(struct xfs_agfl) : 0)) / \ sizeof(xfs_agblock_t)) typedef struct xfs_agfl { __be32 agfl_magicnum; __be32 agfl_seqno; uuid_t agfl_uuid; __be64 agfl_lsn; __be32 agfl_crc; __be32 agfl_bno[]; /* actually XFS_AGFL_SIZE(mp) */ } xfs_agfl_t; #define XFS_AGFL_CRC_OFF offsetof(struct xfs_agfl, agfl_crc) #define XFS_AGB_TO_FSB(mp,agno,agbno) \ (((xfs_fsblock_t)(agno) << (mp)->m_sb.sb_agblklog) | (agbno)) #define XFS_FSB_TO_AGNO(mp,fsbno) \ ((xfs_agnumber_t)((fsbno) >> (mp)->m_sb.sb_agblklog)) #define XFS_FSB_TO_AGBNO(mp,fsbno) \ ((xfs_agblock_t)((fsbno) & xfs_mask32lo((mp)->m_sb.sb_agblklog))) #define XFS_AGB_TO_DADDR(mp,agno,agbno) \ ((xfs_daddr_t)XFS_FSB_TO_BB(mp, \ (xfs_fsblock_t)(agno) * (mp)->m_sb.sb_agblocks + (agbno))) #define XFS_AG_DADDR(mp,agno,d) (XFS_AGB_TO_DADDR(mp, agno, 0) + (d)) /* * For checking for bad ranges of xfs_daddr_t's, covering multiple * allocation groups or a single xfs_daddr_t that's a superblock copy. */ #define XFS_AG_CHECK_DADDR(mp,d,len) \ ((len) == 1 ? \ ASSERT((d) == XFS_SB_DADDR || \ xfs_daddr_to_agbno(mp, d) != XFS_SB_DADDR) : \ ASSERT(xfs_daddr_to_agno(mp, d) == \ xfs_daddr_to_agno(mp, (d) + (len) - 1))) typedef struct xfs_timestamp { __be32 t_sec; /* timestamp seconds */ __be32 t_nsec; /* timestamp nanoseconds */ } xfs_timestamp_t; /* * On-disk inode structure. * * This is just the header or "dinode core", the inode is expanded to fill a * variable size the leftover area split into a data and an attribute fork. * The format of the data and attribute fork depends on the format of the * inode as indicated by di_format and di_aformat. To access the data and * attribute use the XFS_DFORK_DPTR, XFS_DFORK_APTR, and XFS_DFORK_PTR macros * below. * * There is a very similar struct icdinode in xfs_inode which matches the * layout of the first 96 bytes of this structure, but is kept in native * format instead of big endian. * * Note: di_flushiter is only used by v1/2 inodes - it's effectively a zeroed * padding field for v3 inodes. */ #define XFS_DINODE_MAGIC 0x494e /* 'IN' */ typedef struct xfs_dinode { __be16 di_magic; /* inode magic # = XFS_DINODE_MAGIC */ __be16 di_mode; /* mode and type of file */ __u8 di_version; /* inode version */ __u8 di_format; /* format of di_c data */ __be16 di_onlink; /* old number of links to file */ __be32 di_uid; /* owner's user id */ __be32 di_gid; /* owner's group id */ __be32 di_nlink; /* number of links to file */ __be16 di_projid_lo; /* lower part of owner's project id */ __be16 di_projid_hi; /* higher part owner's project id */ __u8 di_pad[6]; /* unused, zeroed space */ __be16 di_flushiter; /* incremented on flush */ xfs_timestamp_t di_atime; /* time last accessed */ xfs_timestamp_t di_mtime; /* time last modified */ xfs_timestamp_t di_ctime; /* time created/inode modified */ __be64 di_size; /* number of bytes in file */ __be64 di_nblocks; /* # of direct & btree blocks used */ __be32 di_extsize; /* basic/minimum extent size for file */ __be32 di_nextents; /* number of extents in data fork */ __be16 di_anextents; /* number of extents in attribute fork*/ __u8 di_forkoff; /* attr fork offs, <<3 for 64b align */ __s8 di_aformat; /* format of attr fork's data */ __be32 di_dmevmask; /* DMIG event mask */ __be16 di_dmstate; /* DMIG state info */ __be16 di_flags; /* random flags, XFS_DIFLAG_... */ __be32 di_gen; /* generation number */ /* di_next_unlinked is the only non-core field in the old dinode */ __be32 di_next_unlinked;/* agi unlinked list ptr */ /* start of the extended dinode, writable fields */ __le32 di_crc; /* CRC of the inode */ __be64 di_changecount; /* number of attribute changes */ __be64 di_lsn; /* flush sequence */ __be64 di_flags2; /* more random flags */ __u8 di_pad2[16]; /* more padding for future expansion */ /* fields only written to during inode creation */ xfs_timestamp_t di_crtime; /* time created */ __be64 di_ino; /* inode number */ uuid_t di_uuid; /* UUID of the filesystem */ /* structure must be padded to 64 bit alignment */ } xfs_dinode_t; #define XFS_DINODE_CRC_OFF offsetof(struct xfs_dinode, di_crc) #define DI_MAX_FLUSH 0xffff /* * Size of the core inode on disk. Version 1 and 2 inodes have * the same size, but version 3 has grown a few additional fields. */ static inline uint xfs_dinode_size(int version) { if (version == 3) return sizeof(struct xfs_dinode); return offsetof(struct xfs_dinode, di_crc); } /* * The 32 bit link count in the inode theoretically maxes out at UINT_MAX. * Since the pathconf interface is signed, we use 2^31 - 1 instead. * The old inode format had a 16 bit link count, so its maximum is USHRT_MAX. */ #define XFS_MAXLINK ((1U << 31) - 1U) #define XFS_MAXLINK_1 65535U /* * Values for di_format */ typedef enum xfs_dinode_fmt { XFS_DINODE_FMT_DEV, /* xfs_dev_t */ XFS_DINODE_FMT_LOCAL, /* bulk data */ XFS_DINODE_FMT_EXTENTS, /* struct xfs_bmbt_rec */ XFS_DINODE_FMT_BTREE, /* struct xfs_bmdr_block */ XFS_DINODE_FMT_UUID /* uuid_t */ } xfs_dinode_fmt_t; /* * Inode minimum and maximum sizes. */ #define XFS_DINODE_MIN_LOG 8 #define XFS_DINODE_MAX_LOG 11 #define XFS_DINODE_MIN_SIZE (1 << XFS_DINODE_MIN_LOG) #define XFS_DINODE_MAX_SIZE (1 << XFS_DINODE_MAX_LOG) /* * Inode size for given fs. */ #define XFS_LITINO(mp, version) \ ((int)(((mp)->m_sb.sb_inodesize) - xfs_dinode_size(version))) /* * Inode data & attribute fork sizes, per inode. */ #define XFS_DFORK_Q(dip) ((dip)->di_forkoff != 0) #define XFS_DFORK_BOFF(dip) ((int)((dip)->di_forkoff << 3)) #define XFS_DFORK_DSIZE(dip,mp) \ (XFS_DFORK_Q(dip) ? \ XFS_DFORK_BOFF(dip) : \ XFS_LITINO(mp, (dip)->di_version)) #define XFS_DFORK_ASIZE(dip,mp) \ (XFS_DFORK_Q(dip) ? \ XFS_LITINO(mp, (dip)->di_version) - XFS_DFORK_BOFF(dip) : \ 0) #define XFS_DFORK_SIZE(dip,mp,w) \ ((w) == XFS_DATA_FORK ? \ XFS_DFORK_DSIZE(dip, mp) : \ XFS_DFORK_ASIZE(dip, mp)) /* * Return pointers to the data or attribute forks. */ #define XFS_DFORK_DPTR(dip) \ ((char *)dip + xfs_dinode_size(dip->di_version)) #define XFS_DFORK_APTR(dip) \ (XFS_DFORK_DPTR(dip) + XFS_DFORK_BOFF(dip)) #define XFS_DFORK_PTR(dip,w) \ ((w) == XFS_DATA_FORK ? XFS_DFORK_DPTR(dip) : XFS_DFORK_APTR(dip)) #define XFS_DFORK_FORMAT(dip,w) \ ((w) == XFS_DATA_FORK ? \ (dip)->di_format : \ (dip)->di_aformat) #define XFS_DFORK_NEXTENTS(dip,w) \ ((w) == XFS_DATA_FORK ? \ be32_to_cpu((dip)->di_nextents) : \ be16_to_cpu((dip)->di_anextents)) /* * For block and character special files the 32bit dev_t is stored at the * beginning of the data fork. */ static inline xfs_dev_t xfs_dinode_get_rdev(struct xfs_dinode *dip) { return be32_to_cpu(*(__be32 *)XFS_DFORK_DPTR(dip)); } static inline void xfs_dinode_put_rdev(struct xfs_dinode *dip, xfs_dev_t rdev) { *(__be32 *)XFS_DFORK_DPTR(dip) = cpu_to_be32(rdev); } /* * Values for di_flags * There should be a one-to-one correspondence between these flags and the * XFS_XFLAG_s. */ #define XFS_DIFLAG_REALTIME_BIT 0 /* file's blocks come from rt area */ #define XFS_DIFLAG_PREALLOC_BIT 1 /* file space has been preallocated */ #define XFS_DIFLAG_NEWRTBM_BIT 2 /* for rtbitmap inode, new format */ #define XFS_DIFLAG_IMMUTABLE_BIT 3 /* inode is immutable */ #define XFS_DIFLAG_APPEND_BIT 4 /* inode is append-only */ #define XFS_DIFLAG_SYNC_BIT 5 /* inode is written synchronously */ #define XFS_DIFLAG_NOATIME_BIT 6 /* do not update atime */ #define XFS_DIFLAG_NODUMP_BIT 7 /* do not dump */ #define XFS_DIFLAG_RTINHERIT_BIT 8 /* create with realtime bit set */ #define XFS_DIFLAG_PROJINHERIT_BIT 9 /* create with parents projid */ #define XFS_DIFLAG_NOSYMLINKS_BIT 10 /* disallow symlink creation */ #define XFS_DIFLAG_EXTSIZE_BIT 11 /* inode extent size allocator hint */ #define XFS_DIFLAG_EXTSZINHERIT_BIT 12 /* inherit inode extent size */ #define XFS_DIFLAG_NODEFRAG_BIT 13 /* do not reorganize/defragment */ #define XFS_DIFLAG_FILESTREAM_BIT 14 /* use filestream allocator */ #define XFS_DIFLAG_REALTIME (1 << XFS_DIFLAG_REALTIME_BIT) #define XFS_DIFLAG_PREALLOC (1 << XFS_DIFLAG_PREALLOC_BIT) #define XFS_DIFLAG_NEWRTBM (1 << XFS_DIFLAG_NEWRTBM_BIT) #define XFS_DIFLAG_IMMUTABLE (1 << XFS_DIFLAG_IMMUTABLE_BIT) #define XFS_DIFLAG_APPEND (1 << XFS_DIFLAG_APPEND_BIT) #define XFS_DIFLAG_SYNC (1 << XFS_DIFLAG_SYNC_BIT) #define XFS_DIFLAG_NOATIME (1 << XFS_DIFLAG_NOATIME_BIT) #define XFS_DIFLAG_NODUMP (1 << XFS_DIFLAG_NODUMP_BIT) #define XFS_DIFLAG_RTINHERIT (1 << XFS_DIFLAG_RTINHERIT_BIT) #define XFS_DIFLAG_PROJINHERIT (1 << XFS_DIFLAG_PROJINHERIT_BIT) #define XFS_DIFLAG_NOSYMLINKS (1 << XFS_DIFLAG_NOSYMLINKS_BIT) #define XFS_DIFLAG_EXTSIZE (1 << XFS_DIFLAG_EXTSIZE_BIT) #define XFS_DIFLAG_EXTSZINHERIT (1 << XFS_DIFLAG_EXTSZINHERIT_BIT) #define XFS_DIFLAG_NODEFRAG (1 << XFS_DIFLAG_NODEFRAG_BIT) #define XFS_DIFLAG_FILESTREAM (1 << XFS_DIFLAG_FILESTREAM_BIT) #define XFS_DIFLAG_ANY \ (XFS_DIFLAG_REALTIME | XFS_DIFLAG_PREALLOC | XFS_DIFLAG_NEWRTBM | \ XFS_DIFLAG_IMMUTABLE | XFS_DIFLAG_APPEND | XFS_DIFLAG_SYNC | \ XFS_DIFLAG_NOATIME | XFS_DIFLAG_NODUMP | XFS_DIFLAG_RTINHERIT | \ XFS_DIFLAG_PROJINHERIT | XFS_DIFLAG_NOSYMLINKS | XFS_DIFLAG_EXTSIZE | \ XFS_DIFLAG_EXTSZINHERIT | XFS_DIFLAG_NODEFRAG | XFS_DIFLAG_FILESTREAM) /* * Inode number format: * low inopblog bits - offset in block * next agblklog bits - block number in ag * next agno_log bits - ag number * high agno_log-agblklog-inopblog bits - 0 */ #define XFS_INO_MASK(k) (__uint32_t)((1ULL << (k)) - 1) #define XFS_INO_OFFSET_BITS(mp) (mp)->m_sb.sb_inopblog #define XFS_INO_AGBNO_BITS(mp) (mp)->m_sb.sb_agblklog #define XFS_INO_AGINO_BITS(mp) (mp)->m_agino_log #define XFS_INO_AGNO_BITS(mp) (mp)->m_agno_log #define XFS_INO_BITS(mp) \ XFS_INO_AGNO_BITS(mp) + XFS_INO_AGINO_BITS(mp) #define XFS_INO_TO_AGNO(mp,i) \ ((xfs_agnumber_t)((i) >> XFS_INO_AGINO_BITS(mp))) #define XFS_INO_TO_AGINO(mp,i) \ ((xfs_agino_t)(i) & XFS_INO_MASK(XFS_INO_AGINO_BITS(mp))) #define XFS_INO_TO_AGBNO(mp,i) \ (((xfs_agblock_t)(i) >> XFS_INO_OFFSET_BITS(mp)) & \ XFS_INO_MASK(XFS_INO_AGBNO_BITS(mp))) #define XFS_INO_TO_OFFSET(mp,i) \ ((int)(i) & XFS_INO_MASK(XFS_INO_OFFSET_BITS(mp))) #define XFS_INO_TO_FSB(mp,i) \ XFS_AGB_TO_FSB(mp, XFS_INO_TO_AGNO(mp,i), XFS_INO_TO_AGBNO(mp,i)) #define XFS_AGINO_TO_INO(mp,a,i) \ (((xfs_ino_t)(a) << XFS_INO_AGINO_BITS(mp)) | (i)) #define XFS_AGINO_TO_AGBNO(mp,i) ((i) >> XFS_INO_OFFSET_BITS(mp)) #define XFS_AGINO_TO_OFFSET(mp,i) \ ((i) & XFS_INO_MASK(XFS_INO_OFFSET_BITS(mp))) #define XFS_OFFBNO_TO_AGINO(mp,b,o) \ ((xfs_agino_t)(((b) << XFS_INO_OFFSET_BITS(mp)) | (o))) #define XFS_MAXINUMBER ((xfs_ino_t)((1ULL << 56) - 1ULL)) #define XFS_MAXINUMBER_32 ((xfs_ino_t)((1ULL << 32) - 1ULL)) /* * RealTime Device format definitions */ /* Min and max rt extent sizes, specified in bytes */ #define XFS_MAX_RTEXTSIZE (1024 * 1024 * 1024) /* 1GB */ #define XFS_DFL_RTEXTSIZE (64 * 1024) /* 64kB */ #define XFS_MIN_RTEXTSIZE (4 * 1024) /* 4kB */ #define XFS_BLOCKSIZE(mp) ((mp)->m_sb.sb_blocksize) #define XFS_BLOCKMASK(mp) ((mp)->m_blockmask) #define XFS_BLOCKWSIZE(mp) ((mp)->m_blockwsize) #define XFS_BLOCKWMASK(mp) ((mp)->m_blockwmask) /* * RT Summary and bit manipulation macros. */ #define XFS_SUMOFFS(mp,ls,bb) ((int)((ls) * (mp)->m_sb.sb_rbmblocks + (bb))) #define XFS_SUMOFFSTOBLOCK(mp,s) \ (((s) * (uint)sizeof(xfs_suminfo_t)) >> (mp)->m_sb.sb_blocklog) #define XFS_SUMPTR(mp,bp,so) \ ((xfs_suminfo_t *)((bp)->b_addr + \ (((so) * (uint)sizeof(xfs_suminfo_t)) & XFS_BLOCKMASK(mp)))) #define XFS_BITTOBLOCK(mp,bi) ((bi) >> (mp)->m_blkbit_log) #define XFS_BLOCKTOBIT(mp,bb) ((bb) << (mp)->m_blkbit_log) #define XFS_BITTOWORD(mp,bi) \ ((int)(((bi) >> XFS_NBWORDLOG) & XFS_BLOCKWMASK(mp))) #define XFS_RTMIN(a,b) ((a) < (b) ? (a) : (b)) #define XFS_RTMAX(a,b) ((a) > (b) ? (a) : (b)) #define XFS_RTLOBIT(w) xfs_lowbit32(w) #define XFS_RTHIBIT(w) xfs_highbit32(w) #define XFS_RTBLOCKLOG(b) xfs_highbit64(b) /* * Dquot and dquot block format definitions */ #define XFS_DQUOT_MAGIC 0x4451 /* 'DQ' */ #define XFS_DQUOT_VERSION (u_int8_t)0x01 /* latest version number */ /* * This is the main portion of the on-disk representation of quota * information for a user. This is the q_core of the xfs_dquot_t that * is kept in kernel memory. We pad this with some more expansion room * to construct the on disk structure. */ typedef struct xfs_disk_dquot { __be16 d_magic; /* dquot magic = XFS_DQUOT_MAGIC */ __u8 d_version; /* dquot version */ __u8 d_flags; /* XFS_DQ_USER/PROJ/GROUP */ __be32 d_id; /* user,project,group id */ __be64 d_blk_hardlimit;/* absolute limit on disk blks */ __be64 d_blk_softlimit;/* preferred limit on disk blks */ __be64 d_ino_hardlimit;/* maximum # allocated inodes */ __be64 d_ino_softlimit;/* preferred inode limit */ __be64 d_bcount; /* disk blocks owned by the user */ __be64 d_icount; /* inodes owned by the user */ __be32 d_itimer; /* zero if within inode limits if not, this is when we refuse service */ __be32 d_btimer; /* similar to above; for disk blocks */ __be16 d_iwarns; /* warnings issued wrt num inodes */ __be16 d_bwarns; /* warnings issued wrt disk blocks */ __be32 d_pad0; /* 64 bit align */ __be64 d_rtb_hardlimit;/* absolute limit on realtime blks */ __be64 d_rtb_softlimit;/* preferred limit on RT disk blks */ __be64 d_rtbcount; /* realtime blocks owned */ __be32 d_rtbtimer; /* similar to above; for RT disk blocks */ __be16 d_rtbwarns; /* warnings issued wrt RT disk blocks */ __be16 d_pad; } xfs_disk_dquot_t; /* * This is what goes on disk. This is separated from the xfs_disk_dquot because * carrying the unnecessary padding would be a waste of memory. */ typedef struct xfs_dqblk { xfs_disk_dquot_t dd_diskdq; /* portion that lives incore as well */ char dd_fill[4]; /* filling for posterity */ /* * These two are only present on filesystems with the CRC bits set. */ __be32 dd_crc; /* checksum */ __be64 dd_lsn; /* last modification in log */ uuid_t dd_uuid; /* location information */ } xfs_dqblk_t; #define XFS_DQUOT_CRC_OFF offsetof(struct xfs_dqblk, dd_crc) /* * Remote symlink format and access functions. */ #define XFS_SYMLINK_MAGIC 0x58534c4d /* XSLM */ struct xfs_dsymlink_hdr { __be32 sl_magic; __be32 sl_offset; __be32 sl_bytes; __be32 sl_crc; uuid_t sl_uuid; __be64 sl_owner; __be64 sl_blkno; __be64 sl_lsn; }; #define XFS_SYMLINK_CRC_OFF offsetof(struct xfs_dsymlink_hdr, sl_crc) /* * The maximum pathlen is 1024 bytes. Since the minimum file system * blocksize is 512 bytes, we can get a max of 3 extents back from * bmapi when crc headers are taken into account. */ #define XFS_SYMLINK_MAPS 3 #define XFS_SYMLINK_BUF_SPACE(mp, bufsize) \ ((bufsize) - (xfs_sb_version_hascrc(&(mp)->m_sb) ? \ sizeof(struct xfs_dsymlink_hdr) : 0)) /* * Allocation Btree format definitions * * There are two on-disk btrees, one sorted by blockno and one sorted * by blockcount and blockno. All blocks look the same to make the code * simpler; if we have time later, we'll make the optimizations. */ #define XFS_ABTB_MAGIC 0x41425442 /* 'ABTB' for bno tree */ #define XFS_ABTB_CRC_MAGIC 0x41423342 /* 'AB3B' */ #define XFS_ABTC_MAGIC 0x41425443 /* 'ABTC' for cnt tree */ #define XFS_ABTC_CRC_MAGIC 0x41423343 /* 'AB3C' */ /* * Data record/key structure */ typedef struct xfs_alloc_rec { __be32 ar_startblock; /* starting block number */ __be32 ar_blockcount; /* count of free blocks */ } xfs_alloc_rec_t, xfs_alloc_key_t; typedef struct xfs_alloc_rec_incore { xfs_agblock_t ar_startblock; /* starting block number */ xfs_extlen_t ar_blockcount; /* count of free blocks */ } xfs_alloc_rec_incore_t; /* btree pointer type */ typedef __be32 xfs_alloc_ptr_t; /* * Block numbers in the AG: * SB is sector 0, AGF is sector 1, AGI is sector 2, AGFL is sector 3. */ #define XFS_BNO_BLOCK(mp) ((xfs_agblock_t)(XFS_AGFL_BLOCK(mp) + 1)) #define XFS_CNT_BLOCK(mp) ((xfs_agblock_t)(XFS_BNO_BLOCK(mp) + 1)) /* * Inode Allocation Btree format definitions * * There is a btree for the inode map per allocation group. */ #define XFS_IBT_MAGIC 0x49414254 /* 'IABT' */ #define XFS_IBT_CRC_MAGIC 0x49414233 /* 'IAB3' */ #define XFS_FIBT_MAGIC 0x46494254 /* 'FIBT' */ #define XFS_FIBT_CRC_MAGIC 0x46494233 /* 'FIB3' */ typedef __uint64_t xfs_inofree_t; #define XFS_INODES_PER_CHUNK (NBBY * sizeof(xfs_inofree_t)) #define XFS_INODES_PER_CHUNK_LOG (XFS_NBBYLOG + 3) #define XFS_INOBT_ALL_FREE ((xfs_inofree_t)-1) #define XFS_INOBT_MASK(i) ((xfs_inofree_t)1 << (i)) #define XFS_INOBT_HOLEMASK_FULL 0 /* holemask for full chunk */ #define XFS_INOBT_HOLEMASK_BITS (NBBY * sizeof(__uint16_t)) #define XFS_INODES_PER_HOLEMASK_BIT \ (XFS_INODES_PER_CHUNK / (NBBY * sizeof(__uint16_t))) static inline xfs_inofree_t xfs_inobt_maskn(int i, int n) { return ((n >= XFS_INODES_PER_CHUNK ? 0 : XFS_INOBT_MASK(n)) - 1) << i; } /* * The on-disk inode record structure has two formats. The original "full" * format uses a 4-byte freecount. The "sparse" format uses a 1-byte freecount * and replaces the 3 high-order freecount bytes wth the holemask and inode * count. * * The holemask of the sparse record format allows an inode chunk to have holes * that refer to blocks not owned by the inode record. This facilitates inode * allocation in the event of severe free space fragmentation. */ typedef struct xfs_inobt_rec { __be32 ir_startino; /* starting inode number */ union { struct { __be32 ir_freecount; /* count of free inodes */ } f; struct { __be16 ir_holemask;/* hole mask for sparse chunks */ __u8 ir_count; /* total inode count */ __u8 ir_freecount; /* count of free inodes */ } sp; } ir_u; __be64 ir_free; /* free inode mask */ } xfs_inobt_rec_t; typedef struct xfs_inobt_rec_incore { xfs_agino_t ir_startino; /* starting inode number */ __uint16_t ir_holemask; /* hole mask for sparse chunks */ __uint8_t ir_count; /* total inode count */ __uint8_t ir_freecount; /* count of free inodes (set bits) */ xfs_inofree_t ir_free; /* free inode mask */ } xfs_inobt_rec_incore_t; static inline bool xfs_inobt_issparse(uint16_t holemask) { /* non-zero holemask represents a sparse rec. */ return holemask; } /* * Key structure */ typedef struct xfs_inobt_key { __be32 ir_startino; /* starting inode number */ } xfs_inobt_key_t; /* btree pointer type */ typedef __be32 xfs_inobt_ptr_t; /* * block numbers in the AG. */ #define XFS_IBT_BLOCK(mp) ((xfs_agblock_t)(XFS_CNT_BLOCK(mp) + 1)) #define XFS_FIBT_BLOCK(mp) ((xfs_agblock_t)(XFS_IBT_BLOCK(mp) + 1)) /* * The first data block of an AG depends on whether the filesystem was formatted * with the finobt feature. If so, account for the finobt reserved root btree * block. */ #define XFS_PREALLOC_BLOCKS(mp) \ (xfs_sb_version_hasfinobt(&((mp)->m_sb)) ? \ XFS_FIBT_BLOCK(mp) + 1 : \ XFS_IBT_BLOCK(mp) + 1) /* * BMAP Btree format definitions * * This includes both the root block definition that sits inside an inode fork * and the record/pointer formats for the leaf/node in the blocks. */ #define XFS_BMAP_MAGIC 0x424d4150 /* 'BMAP' */ #define XFS_BMAP_CRC_MAGIC 0x424d4133 /* 'BMA3' */ /* * Bmap root header, on-disk form only. */ typedef struct xfs_bmdr_block { __be16 bb_level; /* 0 is a leaf */ __be16 bb_numrecs; /* current # of data records */ } xfs_bmdr_block_t; /* * Bmap btree record and extent descriptor. * l0:63 is an extent flag (value 1 indicates non-normal). * l0:9-62 are startoff. * l0:0-8 and l1:21-63 are startblock. * l1:0-20 are blockcount. */ #define BMBT_EXNTFLAG_BITLEN 1 #define BMBT_STARTOFF_BITLEN 54 #define BMBT_STARTBLOCK_BITLEN 52 #define BMBT_BLOCKCOUNT_BITLEN 21 typedef struct xfs_bmbt_rec { __be64 l0, l1; } xfs_bmbt_rec_t; typedef __uint64_t xfs_bmbt_rec_base_t; /* use this for casts */ typedef xfs_bmbt_rec_t xfs_bmdr_rec_t; typedef struct xfs_bmbt_rec_host { __uint64_t l0, l1; } xfs_bmbt_rec_host_t; /* * Values and macros for delayed-allocation startblock fields. */ #define STARTBLOCKVALBITS 17 #define STARTBLOCKMASKBITS (15 + 20) #define STARTBLOCKMASK \ (((((xfs_fsblock_t)1) << STARTBLOCKMASKBITS) - 1) << STARTBLOCKVALBITS) static inline int isnullstartblock(xfs_fsblock_t x) { return ((x) & STARTBLOCKMASK) == STARTBLOCKMASK; } static inline xfs_fsblock_t nullstartblock(int k) { ASSERT(k < (1 << STARTBLOCKVALBITS)); return STARTBLOCKMASK | (k); } static inline xfs_filblks_t startblockval(xfs_fsblock_t x) { return (xfs_filblks_t)((x) & ~STARTBLOCKMASK); } /* * Possible extent formats. */ typedef enum { XFS_EXTFMT_NOSTATE = 0, XFS_EXTFMT_HASSTATE } xfs_exntfmt_t; /* * Possible extent states. */ typedef enum { XFS_EXT_NORM, XFS_EXT_UNWRITTEN, XFS_EXT_DMAPI_OFFLINE, XFS_EXT_INVALID } xfs_exntst_t; /* * Incore version of above. */ typedef struct xfs_bmbt_irec { xfs_fileoff_t br_startoff; /* starting file offset */ xfs_fsblock_t br_startblock; /* starting block number */ xfs_filblks_t br_blockcount; /* number of blocks */ xfs_exntst_t br_state; /* extent state */ } xfs_bmbt_irec_t; /* * Key structure for non-leaf levels of the tree. */ typedef struct xfs_bmbt_key { __be64 br_startoff; /* starting file offset */ } xfs_bmbt_key_t, xfs_bmdr_key_t; /* btree pointer type */ typedef __be64 xfs_bmbt_ptr_t, xfs_bmdr_ptr_t; /* * Generic Btree block format definitions * * This is a combination of the actual format used on disk for short and long * format btrees. The first three fields are shared by both format, but the * pointers are different and should be used with care. * * To get the size of the actual short or long form headers please use the size * macros below. Never use sizeof(xfs_btree_block). * * The blkno, crc, lsn, owner and uuid fields are only available in filesystems * with the crc feature bit, and all accesses to them must be conditional on * that flag. */ struct xfs_btree_block { __be32 bb_magic; /* magic number for block type */ __be16 bb_level; /* 0 is a leaf */ __be16 bb_numrecs; /* current # of data records */ union { struct { __be32 bb_leftsib; __be32 bb_rightsib; __be64 bb_blkno; __be64 bb_lsn; uuid_t bb_uuid; __be32 bb_owner; __le32 bb_crc; } s; /* short form pointers */ struct { __be64 bb_leftsib; __be64 bb_rightsib; __be64 bb_blkno; __be64 bb_lsn; uuid_t bb_uuid; __be64 bb_owner; __le32 bb_crc; __be32 bb_pad; /* padding for alignment */ } l; /* long form pointers */ } bb_u; /* rest */ }; #define XFS_BTREE_SBLOCK_LEN 16 /* size of a short form block */ #define XFS_BTREE_LBLOCK_LEN 24 /* size of a long form block */ /* sizes of CRC enabled btree blocks */ #define XFS_BTREE_SBLOCK_CRC_LEN (XFS_BTREE_SBLOCK_LEN + 40) #define XFS_BTREE_LBLOCK_CRC_LEN (XFS_BTREE_LBLOCK_LEN + 48) #define XFS_BTREE_SBLOCK_CRC_OFF \ offsetof(struct xfs_btree_block, bb_u.s.bb_crc) #define XFS_BTREE_LBLOCK_CRC_OFF \ offsetof(struct xfs_btree_block, bb_u.l.bb_crc) /* * On-disk XFS access control list structure. */ struct xfs_acl_entry { __be32 ae_tag; __be32 ae_id; __be16 ae_perm; __be16 ae_pad; /* fill the implicit hole in the structure */ }; struct xfs_acl { __be32 acl_cnt; struct xfs_acl_entry acl_entry[0]; }; /* * The number of ACL entries allowed is defined by the on-disk format. * For v4 superblocks, that is limited to 25 entries. For v5 superblocks, it is * limited only by the maximum size of the xattr that stores the information. */ #define XFS_ACL_MAX_ENTRIES(mp) \ (xfs_sb_version_hascrc(&mp->m_sb) \ ? (XATTR_SIZE_MAX - sizeof(struct xfs_acl)) / \ sizeof(struct xfs_acl_entry) \ : 25) #define XFS_ACL_MAX_SIZE(mp) \ (sizeof(struct xfs_acl) + \ sizeof(struct xfs_acl_entry) * XFS_ACL_MAX_ENTRIES((mp))) /* On-disk XFS extended attribute names */ #define SGI_ACL_FILE "SGI_ACL_FILE" #define SGI_ACL_DEFAULT "SGI_ACL_DEFAULT" #define SGI_ACL_FILE_SIZE (sizeof(SGI_ACL_FILE)-1) #define SGI_ACL_DEFAULT_SIZE (sizeof(SGI_ACL_DEFAULT)-1) #endif /* __XFS_FORMAT_H__ */ partclone-0.2.86/src/xfs/xfs_fs.h000066400000000000000000000524241262102574200166360ustar00rootroot00000000000000/* * Copyright (c) 1995-2005 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __XFS_FS_H__ #define __XFS_FS_H__ /* * SGI's XFS filesystem's major stuff (constants, structures) */ /* * Direct I/O attribute record used with XFS_IOC_DIOINFO * d_miniosz is the min xfer size, xfer size multiple and file seek offset * alignment. */ #ifndef HAVE_DIOATTR struct dioattr { __u32 d_mem; /* data buffer memory alignment */ __u32 d_miniosz; /* min xfer size */ __u32 d_maxiosz; /* max xfer size */ }; #endif /* * Structure for XFS_IOC_FSGETXATTR[A] and XFS_IOC_FSSETXATTR. */ #ifndef HAVE_FSXATTR struct fsxattr { __u32 fsx_xflags; /* xflags field value (get/set) */ __u32 fsx_extsize; /* extsize field value (get/set)*/ __u32 fsx_nextents; /* nextents field value (get) */ __u32 fsx_projid; /* project identifier (get/set) */ unsigned char fsx_pad[12]; }; #endif /* * Flags for the bs_xflags/fsx_xflags field * There should be a one-to-one correspondence between these flags and the * XFS_DIFLAG_s. */ #define XFS_XFLAG_REALTIME 0x00000001 /* data in realtime volume */ #define XFS_XFLAG_PREALLOC 0x00000002 /* preallocated file extents */ #define XFS_XFLAG_IMMUTABLE 0x00000008 /* file cannot be modified */ #define XFS_XFLAG_APPEND 0x00000010 /* all writes append */ #define XFS_XFLAG_SYNC 0x00000020 /* all writes synchronous */ #define XFS_XFLAG_NOATIME 0x00000040 /* do not update access time */ #define XFS_XFLAG_NODUMP 0x00000080 /* do not include in backups */ #define XFS_XFLAG_RTINHERIT 0x00000100 /* create with rt bit set */ #define XFS_XFLAG_PROJINHERIT 0x00000200 /* create with parents projid */ #define XFS_XFLAG_NOSYMLINKS 0x00000400 /* disallow symlink creation */ #define XFS_XFLAG_EXTSIZE 0x00000800 /* extent size allocator hint */ #define XFS_XFLAG_EXTSZINHERIT 0x00001000 /* inherit inode extent size */ #define XFS_XFLAG_NODEFRAG 0x00002000 /* do not defragment */ #define XFS_XFLAG_FILESTREAM 0x00004000 /* use filestream allocator */ #define XFS_XFLAG_HASATTR 0x80000000 /* no DIFLAG for this */ /* * Structure for XFS_IOC_GETBMAP. * On input, fill in bmv_offset and bmv_length of the first structure * to indicate the area of interest in the file, and bmv_entries with * the number of array elements given back. The first structure is * updated on return to give the offset and length for the next call. */ #ifndef HAVE_GETBMAP struct getbmap { __s64 bmv_offset; /* file offset of segment in blocks */ __s64 bmv_block; /* starting block (64-bit daddr_t) */ __s64 bmv_length; /* length of segment, blocks */ __s32 bmv_count; /* # of entries in array incl. 1st */ __s32 bmv_entries; /* # of entries filled in (output) */ }; #endif /* * Structure for XFS_IOC_GETBMAPX. Fields bmv_offset through bmv_entries * are used exactly as in the getbmap structure. The getbmapx structure * has additional bmv_iflags and bmv_oflags fields. The bmv_iflags field * is only used for the first structure. It contains input flags * specifying XFS_IOC_GETBMAPX actions. The bmv_oflags field is filled * in by the XFS_IOC_GETBMAPX command for each returned structure after * the first. */ #ifndef HAVE_GETBMAPX struct getbmapx { __s64 bmv_offset; /* file offset of segment in blocks */ __s64 bmv_block; /* starting block (64-bit daddr_t) */ __s64 bmv_length; /* length of segment, blocks */ __s32 bmv_count; /* # of entries in array incl. 1st */ __s32 bmv_entries; /* # of entries filled in (output). */ __s32 bmv_iflags; /* input flags (1st structure) */ __s32 bmv_oflags; /* output flags (after 1st structure)*/ __s32 bmv_unused1; /* future use */ __s32 bmv_unused2; /* future use */ }; #endif /* bmv_iflags values - set by XFS_IOC_GETBMAPX caller. */ #define BMV_IF_ATTRFORK 0x1 /* return attr fork rather than data */ #define BMV_IF_NO_DMAPI_READ 0x2 /* Do not generate DMAPI read event */ #define BMV_IF_PREALLOC 0x4 /* rtn status BMV_OF_PREALLOC if req */ #define BMV_IF_DELALLOC 0x8 /* rtn status BMV_OF_DELALLOC if req */ #define BMV_IF_NO_HOLES 0x10 /* Do not return holes */ #define BMV_IF_VALID \ (BMV_IF_ATTRFORK|BMV_IF_NO_DMAPI_READ|BMV_IF_PREALLOC| \ BMV_IF_DELALLOC|BMV_IF_NO_HOLES) /* bmv_oflags values - returned for each non-header segment */ #define BMV_OF_PREALLOC 0x1 /* segment = unwritten pre-allocation */ #define BMV_OF_DELALLOC 0x2 /* segment = delayed allocation */ #define BMV_OF_LAST 0x4 /* segment is the last in the file */ /* * Structure for XFS_IOC_FSSETDM. * For use by backup and restore programs to set the XFS on-disk inode * fields di_dmevmask and di_dmstate. These must be set to exactly and * only values previously obtained via xfs_bulkstat! (Specifically the * xfs_bstat_t fields bs_dmevmask and bs_dmstate.) */ #ifndef HAVE_FSDMIDATA struct fsdmidata { __u32 fsd_dmevmask; /* corresponds to di_dmevmask */ __u16 fsd_padding; __u16 fsd_dmstate; /* corresponds to di_dmstate */ }; #endif /* * File segment locking set data type for 64 bit access. * Also used for all the RESV/FREE interfaces. */ typedef struct xfs_flock64 { __s16 l_type; __s16 l_whence; __s64 l_start; __s64 l_len; /* len == 0 means until end of file */ __s32 l_sysid; __u32 l_pid; __s32 l_pad[4]; /* reserve area */ } xfs_flock64_t; /* * Output for XFS_IOC_FSGEOMETRY_V1 */ typedef struct xfs_fsop_geom_v1 { __u32 blocksize; /* filesystem (data) block size */ __u32 rtextsize; /* realtime extent size */ __u32 agblocks; /* fsblocks in an AG */ __u32 agcount; /* number of allocation groups */ __u32 logblocks; /* fsblocks in the log */ __u32 sectsize; /* (data) sector size, bytes */ __u32 inodesize; /* inode size in bytes */ __u32 imaxpct; /* max allowed inode space(%) */ __u64 datablocks; /* fsblocks in data subvolume */ __u64 rtblocks; /* fsblocks in realtime subvol */ __u64 rtextents; /* rt extents in realtime subvol*/ __u64 logstart; /* starting fsblock of the log */ unsigned char uuid[16]; /* unique id of the filesystem */ __u32 sunit; /* stripe unit, fsblocks */ __u32 swidth; /* stripe width, fsblocks */ __s32 version; /* structure version */ __u32 flags; /* superblock version flags */ __u32 logsectsize; /* log sector size, bytes */ __u32 rtsectsize; /* realtime sector size, bytes */ __u32 dirblocksize; /* directory block size, bytes */ } xfs_fsop_geom_v1_t; /* * Output for XFS_IOC_FSGEOMETRY */ typedef struct xfs_fsop_geom { __u32 blocksize; /* filesystem (data) block size */ __u32 rtextsize; /* realtime extent size */ __u32 agblocks; /* fsblocks in an AG */ __u32 agcount; /* number of allocation groups */ __u32 logblocks; /* fsblocks in the log */ __u32 sectsize; /* (data) sector size, bytes */ __u32 inodesize; /* inode size in bytes */ __u32 imaxpct; /* max allowed inode space(%) */ __u64 datablocks; /* fsblocks in data subvolume */ __u64 rtblocks; /* fsblocks in realtime subvol */ __u64 rtextents; /* rt extents in realtime subvol*/ __u64 logstart; /* starting fsblock of the log */ unsigned char uuid[16]; /* unique id of the filesystem */ __u32 sunit; /* stripe unit, fsblocks */ __u32 swidth; /* stripe width, fsblocks */ __s32 version; /* structure version */ __u32 flags; /* superblock version flags */ __u32 logsectsize; /* log sector size, bytes */ __u32 rtsectsize; /* realtime sector size, bytes */ __u32 dirblocksize; /* directory block size, bytes */ __u32 logsunit; /* log stripe unit, bytes */ } xfs_fsop_geom_t; /* Output for XFS_FS_COUNTS */ typedef struct xfs_fsop_counts { __u64 freedata; /* free data section blocks */ __u64 freertx; /* free rt extents */ __u64 freeino; /* free inodes */ __u64 allocino; /* total allocated inodes */ } xfs_fsop_counts_t; /* Input/Output for XFS_GET_RESBLKS and XFS_SET_RESBLKS */ typedef struct xfs_fsop_resblks { __u64 resblks; __u64 resblks_avail; } xfs_fsop_resblks_t; #define XFS_FSOP_GEOM_VERSION 0 #define XFS_FSOP_GEOM_FLAGS_ATTR 0x0001 /* attributes in use */ #define XFS_FSOP_GEOM_FLAGS_NLINK 0x0002 /* 32-bit nlink values */ #define XFS_FSOP_GEOM_FLAGS_QUOTA 0x0004 /* quotas enabled */ #define XFS_FSOP_GEOM_FLAGS_IALIGN 0x0008 /* inode alignment */ #define XFS_FSOP_GEOM_FLAGS_DALIGN 0x0010 /* large data alignment */ #define XFS_FSOP_GEOM_FLAGS_SHARED 0x0020 /* read-only shared */ #define XFS_FSOP_GEOM_FLAGS_EXTFLG 0x0040 /* special extent flag */ #define XFS_FSOP_GEOM_FLAGS_DIRV2 0x0080 /* directory version 2 */ #define XFS_FSOP_GEOM_FLAGS_LOGV2 0x0100 /* log format version 2 */ #define XFS_FSOP_GEOM_FLAGS_SECTOR 0x0200 /* sector sizes >1BB */ #define XFS_FSOP_GEOM_FLAGS_ATTR2 0x0400 /* inline attributes rework */ #define XFS_FSOP_GEOM_FLAGS_PROJID32 0x0800 /* 32-bit project IDs */ #define XFS_FSOP_GEOM_FLAGS_DIRV2CI 0x1000 /* ASCII only CI names */ #define XFS_FSOP_GEOM_FLAGS_LAZYSB 0x4000 /* lazy superblock counters */ #define XFS_FSOP_GEOM_FLAGS_V5SB 0x8000 /* version 5 superblock */ #define XFS_FSOP_GEOM_FLAGS_FTYPE 0x10000 /* inode directory types */ #define XFS_FSOP_GEOM_FLAGS_FINOBT 0x20000 /* free inode btree */ #define XFS_FSOP_GEOM_FLAGS_SPINODES 0x40000 /* sparse inode chunks */ /* * Minimum and maximum sizes need for growth checks. * * Block counts are in units of filesystem blocks, not basic blocks. */ #define XFS_MIN_AG_BLOCKS 64 #define XFS_MIN_LOG_BLOCKS 512ULL #define XFS_MAX_LOG_BLOCKS (1024 * 1024ULL) #define XFS_MIN_LOG_BYTES (10 * 1024 * 1024ULL) /* keep the maximum size under 2^31 by a small amount */ #define XFS_MAX_LOG_BYTES \ ((2 * 1024 * 1024 * 1024ULL) - XFS_MIN_LOG_BYTES) /* Used for sanity checks on superblock */ #define XFS_MAX_DBLOCKS(s) ((xfs_rfsblock_t)(s)->sb_agcount * (s)->sb_agblocks) #define XFS_MIN_DBLOCKS(s) ((xfs_rfsblock_t)((s)->sb_agcount - 1) * \ (s)->sb_agblocks + XFS_MIN_AG_BLOCKS) /* * Structures for XFS_IOC_FSGROWFSDATA, XFS_IOC_FSGROWFSLOG & XFS_IOC_FSGROWFSRT */ typedef struct xfs_growfs_data { __u64 newblocks; /* new data subvol size, fsblocks */ __u32 imaxpct; /* new inode space percentage limit */ } xfs_growfs_data_t; typedef struct xfs_growfs_log { __u32 newblocks; /* new log size, fsblocks */ __u32 isint; /* 1 if new log is internal */ } xfs_growfs_log_t; typedef struct xfs_growfs_rt { __u64 newblocks; /* new realtime size, fsblocks */ __u32 extsize; /* new realtime extent size, fsblocks */ } xfs_growfs_rt_t; /* * Structures returned from ioctl XFS_IOC_FSBULKSTAT & XFS_IOC_FSBULKSTAT_SINGLE */ typedef struct xfs_bstime { time_t tv_sec; /* seconds */ __s32 tv_nsec; /* and nanoseconds */ } xfs_bstime_t; typedef struct xfs_bstat { __u64 bs_ino; /* inode number */ __u16 bs_mode; /* type and mode */ __u16 bs_nlink; /* number of links */ __u32 bs_uid; /* user id */ __u32 bs_gid; /* group id */ __u32 bs_rdev; /* device value */ __s32 bs_blksize; /* block size */ __s64 bs_size; /* file size */ xfs_bstime_t bs_atime; /* access time */ xfs_bstime_t bs_mtime; /* modify time */ xfs_bstime_t bs_ctime; /* inode change time */ int64_t bs_blocks; /* number of blocks */ __u32 bs_xflags; /* extended flags */ __s32 bs_extsize; /* extent size */ __s32 bs_extents; /* number of extents */ __u32 bs_gen; /* generation count */ __u16 bs_projid_lo; /* lower part of project id */ #define bs_projid bs_projid_lo /* (previously just bs_projid) */ __u16 bs_forkoff; /* inode fork offset in bytes */ __u16 bs_projid_hi; /* higher part of project id */ unsigned char bs_pad[10]; /* pad space, unused */ __u32 bs_dmevmask; /* DMIG event mask */ __u16 bs_dmstate; /* DMIG state info */ __u16 bs_aextents; /* attribute number of extents */ } xfs_bstat_t; /* * Project quota id helpers (previously projid was 16bit only * and using two 16bit values to hold new 32bit projid was choosen * to retain compatibility with "old" filesystems). */ static inline __uint32_t bstat_get_projid(struct xfs_bstat *bs) { return (__uint32_t)bs->bs_projid_hi << 16 | bs->bs_projid_lo; } /* * The user-level BulkStat Request interface structure. */ typedef struct xfs_fsop_bulkreq { __u64 __user *lastip; /* last inode # pointer */ __s32 icount; /* count of entries in buffer */ void __user *ubuffer;/* user buffer for inode desc. */ __s32 __user *ocount; /* output count pointer */ } xfs_fsop_bulkreq_t; /* * Structures returned from xfs_inumbers routine (XFS_IOC_FSINUMBERS). */ typedef struct xfs_inogrp { __u64 xi_startino; /* starting inode number */ __s32 xi_alloccount; /* # bits set in allocmask */ __u64 xi_allocmask; /* mask of allocated inodes */ } xfs_inogrp_t; /* * Error injection. */ typedef struct xfs_error_injection { __s32 fd; __s32 errtag; } xfs_error_injection_t; /* * Speculative preallocation trimming. */ #define XFS_EOFBLOCKS_VERSION 1 struct xfs_fs_eofblocks { __u32 eof_version; __u32 eof_flags; uid_t eof_uid; gid_t eof_gid; prid_t eof_prid; __u32 pad32; __u64 eof_min_file_size; __u64 pad64[12]; }; /* eof_flags values */ #define XFS_EOF_FLAGS_SYNC (1 << 0) /* sync/wait mode scan */ #define XFS_EOF_FLAGS_UID (1 << 1) /* filter by uid */ #define XFS_EOF_FLAGS_GID (1 << 2) /* filter by gid */ #define XFS_EOF_FLAGS_PRID (1 << 3) /* filter by project id */ #define XFS_EOF_FLAGS_MINFILESIZE (1 << 4) /* filter by min file size */ #define XFS_EOF_FLAGS_UNION (1 << 5) /* union filter algorithm; * kernel only, not included in * valid mask */ #define XFS_EOF_FLAGS_VALID \ (XFS_EOF_FLAGS_SYNC | \ XFS_EOF_FLAGS_UID | \ XFS_EOF_FLAGS_GID | \ XFS_EOF_FLAGS_PRID | \ XFS_EOF_FLAGS_MINFILESIZE) /* * The user-level Handle Request interface structure. */ typedef struct xfs_fsop_handlereq { __u32 fd; /* fd for FD_TO_HANDLE */ void __user *path; /* user pathname */ __u32 oflags; /* open flags */ void __user *ihandle;/* user supplied handle */ __u32 ihandlen; /* user supplied length */ void __user *ohandle;/* user buffer for handle */ __u32 __user *ohandlen;/* user buffer length */ } xfs_fsop_handlereq_t; /* * Compound structures for passing args through Handle Request interfaces * xfs_fssetdm_by_handle, xfs_attrlist_by_handle, xfs_attrmulti_by_handle * - ioctls: XFS_IOC_FSSETDM_BY_HANDLE, XFS_IOC_ATTRLIST_BY_HANDLE, and * XFS_IOC_ATTRMULTI_BY_HANDLE */ typedef struct xfs_fsop_setdm_handlereq { struct xfs_fsop_handlereq hreq; /* handle information */ struct fsdmidata __user *data; /* DMAPI data */ } xfs_fsop_setdm_handlereq_t; typedef struct xfs_attrlist_cursor { __u32 opaque[4]; } xfs_attrlist_cursor_t; typedef struct xfs_fsop_attrlist_handlereq { struct xfs_fsop_handlereq hreq; /* handle interface structure */ struct xfs_attrlist_cursor pos; /* opaque cookie, list offset */ __u32 flags; /* which namespace to use */ __u32 buflen; /* length of buffer supplied */ void __user *buffer; /* returned names */ } xfs_fsop_attrlist_handlereq_t; typedef struct xfs_attr_multiop { __u32 am_opcode; #define ATTR_OP_GET 1 /* return the indicated attr's value */ #define ATTR_OP_SET 2 /* set/create the indicated attr/value pair */ #define ATTR_OP_REMOVE 3 /* remove the indicated attr */ __s32 am_error; void __user *am_attrname; void __user *am_attrvalue; __u32 am_length; __u32 am_flags; } xfs_attr_multiop_t; typedef struct xfs_fsop_attrmulti_handlereq { struct xfs_fsop_handlereq hreq; /* handle interface structure */ __u32 opcount;/* count of following multiop */ struct xfs_attr_multiop __user *ops; /* attr_multi data */ } xfs_fsop_attrmulti_handlereq_t; /* * per machine unique filesystem identifier types. */ typedef struct { __u32 val[2]; } xfs_fsid_t; /* file system id type */ typedef struct xfs_fid { __u16 fid_len; /* length of remainder */ __u16 fid_pad; __u32 fid_gen; /* generation number */ __u64 fid_ino; /* 64 bits inode number */ } xfs_fid_t; typedef struct xfs_handle { union { __s64 align; /* force alignment of ha_fid */ xfs_fsid_t _ha_fsid; /* unique file system identifier */ } ha_u; xfs_fid_t ha_fid; /* file system specific file ID */ } xfs_handle_t; #define ha_fsid ha_u._ha_fsid #define XFS_HSIZE(handle) (((char *) &(handle).ha_fid.fid_pad \ - (char *) &(handle)) \ + (handle).ha_fid.fid_len) /* * Structure passed to XFS_IOC_SWAPEXT */ typedef struct xfs_swapext { __int64_t sx_version; /* version */ #define XFS_SX_VERSION 0 __int64_t sx_fdtarget; /* fd of target file */ __int64_t sx_fdtmp; /* fd of tmp file */ xfs_off_t sx_offset; /* offset into file */ xfs_off_t sx_length; /* leng from offset */ char sx_pad[16]; /* pad space, unused */ xfs_bstat_t sx_stat; /* stat of target b4 copy */ } xfs_swapext_t; /* * Flags for going down operation */ #define XFS_FSOP_GOING_FLAGS_DEFAULT 0x0 /* going down */ #define XFS_FSOP_GOING_FLAGS_LOGFLUSH 0x1 /* flush log but not data */ #define XFS_FSOP_GOING_FLAGS_NOLOGFLUSH 0x2 /* don't flush log nor data */ /* * ioctl commands that are used by Linux filesystems */ #define XFS_IOC_GETXFLAGS FS_IOC_GETFLAGS #define XFS_IOC_SETXFLAGS FS_IOC_SETFLAGS #define XFS_IOC_GETVERSION FS_IOC_GETVERSION /* * ioctl commands that replace IRIX fcntl()'s * For 'documentation' purposed more than anything else, * the "cmd #" field reflects the IRIX fcntl number. */ #define XFS_IOC_ALLOCSP _IOW ('X', 10, struct xfs_flock64) #define XFS_IOC_FREESP _IOW ('X', 11, struct xfs_flock64) #define XFS_IOC_DIOINFO _IOR ('X', 30, struct dioattr) #define XFS_IOC_FSGETXATTR _IOR ('X', 31, struct fsxattr) #define XFS_IOC_FSSETXATTR _IOW ('X', 32, struct fsxattr) #define XFS_IOC_ALLOCSP64 _IOW ('X', 36, struct xfs_flock64) #define XFS_IOC_FREESP64 _IOW ('X', 37, struct xfs_flock64) #define XFS_IOC_GETBMAP _IOWR('X', 38, struct getbmap) #define XFS_IOC_FSSETDM _IOW ('X', 39, struct fsdmidata) #define XFS_IOC_RESVSP _IOW ('X', 40, struct xfs_flock64) #define XFS_IOC_UNRESVSP _IOW ('X', 41, struct xfs_flock64) #define XFS_IOC_RESVSP64 _IOW ('X', 42, struct xfs_flock64) #define XFS_IOC_UNRESVSP64 _IOW ('X', 43, struct xfs_flock64) #define XFS_IOC_GETBMAPA _IOWR('X', 44, struct getbmap) #define XFS_IOC_FSGETXATTRA _IOR ('X', 45, struct fsxattr) /* XFS_IOC_SETBIOSIZE ---- deprecated 46 */ /* XFS_IOC_GETBIOSIZE ---- deprecated 47 */ #define XFS_IOC_GETBMAPX _IOWR('X', 56, struct getbmap) #define XFS_IOC_ZERO_RANGE _IOW ('X', 57, struct xfs_flock64) #define XFS_IOC_FREE_EOFBLOCKS _IOR ('X', 58, struct xfs_fs_eofblocks) /* * ioctl commands that replace IRIX syssgi()'s */ #define XFS_IOC_FSGEOMETRY_V1 _IOR ('X', 100, struct xfs_fsop_geom_v1) #define XFS_IOC_FSBULKSTAT _IOWR('X', 101, struct xfs_fsop_bulkreq) #define XFS_IOC_FSBULKSTAT_SINGLE _IOWR('X', 102, struct xfs_fsop_bulkreq) #define XFS_IOC_FSINUMBERS _IOWR('X', 103, struct xfs_fsop_bulkreq) #define XFS_IOC_PATH_TO_FSHANDLE _IOWR('X', 104, struct xfs_fsop_handlereq) #define XFS_IOC_PATH_TO_HANDLE _IOWR('X', 105, struct xfs_fsop_handlereq) #define XFS_IOC_FD_TO_HANDLE _IOWR('X', 106, struct xfs_fsop_handlereq) #define XFS_IOC_OPEN_BY_HANDLE _IOWR('X', 107, struct xfs_fsop_handlereq) #define XFS_IOC_READLINK_BY_HANDLE _IOWR('X', 108, struct xfs_fsop_handlereq) #define XFS_IOC_SWAPEXT _IOWR('X', 109, struct xfs_swapext) #define XFS_IOC_FSGROWFSDATA _IOW ('X', 110, struct xfs_growfs_data) #define XFS_IOC_FSGROWFSLOG _IOW ('X', 111, struct xfs_growfs_log) #define XFS_IOC_FSGROWFSRT _IOW ('X', 112, struct xfs_growfs_rt) #define XFS_IOC_FSCOUNTS _IOR ('X', 113, struct xfs_fsop_counts) #define XFS_IOC_SET_RESBLKS _IOWR('X', 114, struct xfs_fsop_resblks) #define XFS_IOC_GET_RESBLKS _IOR ('X', 115, struct xfs_fsop_resblks) #define XFS_IOC_ERROR_INJECTION _IOW ('X', 116, struct xfs_error_injection) #define XFS_IOC_ERROR_CLEARALL _IOW ('X', 117, struct xfs_error_injection) /* XFS_IOC_ATTRCTL_BY_HANDLE -- deprecated 118 */ /* XFS_IOC_FREEZE -- FIFREEZE 119 */ /* XFS_IOC_THAW -- FITHAW 120 */ #ifndef FIFREEZE #define XFS_IOC_FREEZE _IOWR('X', 119, int) #define XFS_IOC_THAW _IOWR('X', 120, int) #endif #define XFS_IOC_FSSETDM_BY_HANDLE _IOW ('X', 121, struct xfs_fsop_setdm_handlereq) #define XFS_IOC_ATTRLIST_BY_HANDLE _IOW ('X', 122, struct xfs_fsop_attrlist_handlereq) #define XFS_IOC_ATTRMULTI_BY_HANDLE _IOW ('X', 123, struct xfs_fsop_attrmulti_handlereq) #define XFS_IOC_FSGEOMETRY _IOR ('X', 124, struct xfs_fsop_geom) #define XFS_IOC_GOINGDOWN _IOR ('X', 125, __uint32_t) /* XFS_IOC_GETFSUUID ---------- deprecated 140 */ #ifndef HAVE_BBMACROS /* * Block I/O parameterization. A basic block (BB) is the lowest size of * filesystem allocation, and must equal 512. Length units given to bio * routines are in BB's. */ #define BBSHIFT 9 #define BBSIZE (1<> BBSHIFT) #define BTOBBT(bytes) ((__u64)(bytes) >> BBSHIFT) #define BBTOB(bbs) ((bbs) << BBSHIFT) #endif #endif /* __XFS_FS_H__ */ partclone-0.2.86/src/xfs/xfs_ialloc.c000066400000000000000000002173031262102574200174630ustar00rootroot00000000000000/* * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_bit.h" #include "xfs_sb.h" #include "xfs_mount.h" #include "xfs_inode.h" #include "xfs_btree.h" #include "xfs_ialloc.h" #include "xfs_ialloc_btree.h" #include "xfs_alloc.h" #include "xfs_bmap.h" #include "xfs_cksum.h" #include "xfs_trans.h" #include "xfs_trace.h" /* * Allocation group level functions. */ static inline int xfs_ialloc_cluster_alignment( struct xfs_mount *mp) { if (xfs_sb_version_hasalign(&mp->m_sb) && mp->m_sb.sb_inoalignmt >= XFS_B_TO_FSBT(mp, mp->m_inode_cluster_size)) return mp->m_sb.sb_inoalignmt; return 1; } /* * Lookup a record by ino in the btree given by cur. */ int /* error */ xfs_inobt_lookup( struct xfs_btree_cur *cur, /* btree cursor */ xfs_agino_t ino, /* starting inode of chunk */ xfs_lookup_t dir, /* <=, >=, == */ int *stat) /* success/failure */ { cur->bc_rec.i.ir_startino = ino; cur->bc_rec.i.ir_holemask = 0; cur->bc_rec.i.ir_count = 0; cur->bc_rec.i.ir_freecount = 0; cur->bc_rec.i.ir_free = 0; return xfs_btree_lookup(cur, dir, stat); } /* * Update the record referred to by cur to the value given. * This either works (return 0) or gets an EFSCORRUPTED error. */ STATIC int /* error */ xfs_inobt_update( struct xfs_btree_cur *cur, /* btree cursor */ xfs_inobt_rec_incore_t *irec) /* btree record */ { union xfs_btree_rec rec; rec.inobt.ir_startino = cpu_to_be32(irec->ir_startino); if (xfs_sb_version_hassparseinodes(&cur->bc_mp->m_sb)) { rec.inobt.ir_u.sp.ir_holemask = cpu_to_be16(irec->ir_holemask); rec.inobt.ir_u.sp.ir_count = irec->ir_count; rec.inobt.ir_u.sp.ir_freecount = irec->ir_freecount; } else { /* ir_holemask/ir_count not supported on-disk */ rec.inobt.ir_u.f.ir_freecount = cpu_to_be32(irec->ir_freecount); } rec.inobt.ir_free = cpu_to_be64(irec->ir_free); return xfs_btree_update(cur, &rec); } /* * Get the data from the pointed-to record. */ int /* error */ xfs_inobt_get_rec( struct xfs_btree_cur *cur, /* btree cursor */ xfs_inobt_rec_incore_t *irec, /* btree record */ int *stat) /* output: success/failure */ { union xfs_btree_rec *rec; int error; error = xfs_btree_get_rec(cur, &rec, stat); if (error || *stat == 0) return error; irec->ir_startino = be32_to_cpu(rec->inobt.ir_startino); if (xfs_sb_version_hassparseinodes(&cur->bc_mp->m_sb)) { irec->ir_holemask = be16_to_cpu(rec->inobt.ir_u.sp.ir_holemask); irec->ir_count = rec->inobt.ir_u.sp.ir_count; irec->ir_freecount = rec->inobt.ir_u.sp.ir_freecount; } else { /* * ir_holemask/ir_count not supported on-disk. Fill in hardcoded * values for full inode chunks. */ irec->ir_holemask = XFS_INOBT_HOLEMASK_FULL; irec->ir_count = XFS_INODES_PER_CHUNK; irec->ir_freecount = be32_to_cpu(rec->inobt.ir_u.f.ir_freecount); } irec->ir_free = be64_to_cpu(rec->inobt.ir_free); return 0; } /* * Insert a single inobt record. Cursor must already point to desired location. */ STATIC int xfs_inobt_insert_rec( struct xfs_btree_cur *cur, __uint16_t holemask, __uint8_t count, __int32_t freecount, xfs_inofree_t free, int *stat) { cur->bc_rec.i.ir_holemask = holemask; cur->bc_rec.i.ir_count = count; cur->bc_rec.i.ir_freecount = freecount; cur->bc_rec.i.ir_free = free; return xfs_btree_insert(cur, stat); } /* * Insert records describing a newly allocated inode chunk into the inobt. */ STATIC int xfs_inobt_insert( struct xfs_mount *mp, struct xfs_trans *tp, struct xfs_buf *agbp, xfs_agino_t newino, xfs_agino_t newlen, xfs_btnum_t btnum) { struct xfs_btree_cur *cur; struct xfs_agi *agi = XFS_BUF_TO_AGI(agbp); xfs_agnumber_t agno = be32_to_cpu(agi->agi_seqno); xfs_agino_t thisino; int i; int error; cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, btnum); for (thisino = newino; thisino < newino + newlen; thisino += XFS_INODES_PER_CHUNK) { error = xfs_inobt_lookup(cur, thisino, XFS_LOOKUP_EQ, &i); if (error) { xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); return error; } ASSERT(i == 0); error = xfs_inobt_insert_rec(cur, XFS_INOBT_HOLEMASK_FULL, XFS_INODES_PER_CHUNK, XFS_INODES_PER_CHUNK, XFS_INOBT_ALL_FREE, &i); if (error) { xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); return error; } ASSERT(i == 1); } xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); return 0; } /* * Verify that the number of free inodes in the AGI is correct. */ #ifdef DEBUG STATIC int xfs_check_agi_freecount( struct xfs_btree_cur *cur, struct xfs_agi *agi) { if (cur->bc_nlevels == 1) { xfs_inobt_rec_incore_t rec; int freecount = 0; int error; int i; error = xfs_inobt_lookup(cur, 0, XFS_LOOKUP_GE, &i); if (error) return error; do { error = xfs_inobt_get_rec(cur, &rec, &i); if (error) return error; if (i) { freecount += rec.ir_freecount; error = xfs_btree_increment(cur, 0, &i); if (error) return error; } } while (i == 1); if (!XFS_FORCED_SHUTDOWN(cur->bc_mp)) ASSERT(freecount == be32_to_cpu(agi->agi_freecount)); } return 0; } #else #define xfs_check_agi_freecount(cur, agi) 0 #endif /* * Initialise a new set of inodes. When called without a transaction context * (e.g. from recovery) we initiate a delayed write of the inode buffers rather * than logging them (which in a transaction context puts them into the AIL * for writeback rather than the xfsbufd queue). */ int xfs_ialloc_inode_init( struct xfs_mount *mp, struct xfs_trans *tp, struct list_head *buffer_list, int icount, xfs_agnumber_t agno, xfs_agblock_t agbno, xfs_agblock_t length, unsigned int gen) { struct xfs_buf *fbuf; struct xfs_dinode *free; int nbufs, blks_per_cluster, inodes_per_cluster; int version; int i, j; xfs_daddr_t d; xfs_ino_t ino = 0; /* * Loop over the new block(s), filling in the inodes. For small block * sizes, manipulate the inodes in buffers which are multiples of the * blocks size. */ blks_per_cluster = xfs_icluster_size_fsb(mp); inodes_per_cluster = blks_per_cluster << mp->m_sb.sb_inopblog; nbufs = length / blks_per_cluster; /* * Figure out what version number to use in the inodes we create. If * the superblock version has caught up to the one that supports the new * inode format, then use the new inode version. Otherwise use the old * version so that old kernels will continue to be able to use the file * system. * * For v3 inodes, we also need to write the inode number into the inode, * so calculate the first inode number of the chunk here as * XFS_OFFBNO_TO_AGINO() only works within a filesystem block, not * across multiple filesystem blocks (such as a cluster) and so cannot * be used in the cluster buffer loop below. * * Further, because we are writing the inode directly into the buffer * and calculating a CRC on the entire inode, we have ot log the entire * inode so that the entire range the CRC covers is present in the log. * That means for v3 inode we log the entire buffer rather than just the * inode cores. */ if (xfs_sb_version_hascrc(&mp->m_sb)) { version = 3; ino = XFS_AGINO_TO_INO(mp, agno, XFS_OFFBNO_TO_AGINO(mp, agbno, 0)); /* * log the initialisation that is about to take place as an * logical operation. This means the transaction does not * need to log the physical changes to the inode buffers as log * recovery will know what initialisation is actually needed. * Hence we only need to log the buffers as "ordered" buffers so * they track in the AIL as if they were physically logged. */ if (tp) xfs_icreate_log(tp, agno, agbno, icount, mp->m_sb.sb_inodesize, length, gen); } else version = 2; for (j = 0; j < nbufs; j++) { /* * Get the block. */ d = XFS_AGB_TO_DADDR(mp, agno, agbno + (j * blks_per_cluster)); fbuf = xfs_trans_get_buf(tp, mp->m_ddev_targp, d, mp->m_bsize * blks_per_cluster, XBF_UNMAPPED); if (!fbuf) return -ENOMEM; /* Initialize the inode buffers and log them appropriately. */ fbuf->b_ops = &xfs_inode_buf_ops; xfs_buf_zero(fbuf, 0, BBTOB(fbuf->b_length)); for (i = 0; i < inodes_per_cluster; i++) { int ioffset = i << mp->m_sb.sb_inodelog; uint isize = xfs_dinode_size(version); free = xfs_make_iptr(mp, fbuf, i); free->di_magic = cpu_to_be16(XFS_DINODE_MAGIC); free->di_version = version; free->di_gen = cpu_to_be32(gen); free->di_next_unlinked = cpu_to_be32(NULLAGINO); if (version == 3) { free->di_ino = cpu_to_be64(ino); ino++; uuid_copy(&free->di_uuid, &mp->m_sb.sb_meta_uuid); xfs_dinode_calc_crc(mp, free); } else if (tp) { /* just log the inode core */ xfs_trans_log_buf(tp, fbuf, ioffset, ioffset + isize - 1); } } if (tp) { /* * Mark the buffer as an inode allocation buffer so it * sticks in AIL at the point of this allocation * transaction. This ensures the they are on disk before * the tail of the log can be moved past this * transaction (i.e. by preventing relogging from moving * it forward in the log). */ xfs_trans_inode_alloc_buf(tp, fbuf); if (version == 3) { /* * Mark the buffer as ordered so that they are * not physically logged in the transaction but * still tracked in the AIL as part of the * transaction and pin the log appropriately. */ xfs_trans_ordered_buf(tp, fbuf); xfs_trans_log_buf(tp, fbuf, 0, BBTOB(fbuf->b_length) - 1); } } else { fbuf->b_flags |= XBF_DONE; xfs_buf_delwri_queue(fbuf, buffer_list); xfs_buf_relse(fbuf); } } return 0; } /* * Align startino and allocmask for a recently allocated sparse chunk such that * they are fit for insertion (or merge) into the on-disk inode btrees. * * Background: * * When enabled, sparse inode support increases the inode alignment from cluster * size to inode chunk size. This means that the minimum range between two * non-adjacent inode records in the inobt is large enough for a full inode * record. This allows for cluster sized, cluster aligned block allocation * without need to worry about whether the resulting inode record overlaps with * another record in the tree. Without this basic rule, we would have to deal * with the consequences of overlap by potentially undoing recent allocations in * the inode allocation codepath. * * Because of this alignment rule (which is enforced on mount), there are two * inobt possibilities for newly allocated sparse chunks. One is that the * aligned inode record for the chunk covers a range of inodes not already * covered in the inobt (i.e., it is safe to insert a new sparse record). The * other is that a record already exists at the aligned startino that considers * the newly allocated range as sparse. In the latter case, record content is * merged in hope that sparse inode chunks fill to full chunks over time. */ STATIC void xfs_align_sparse_ino( struct xfs_mount *mp, xfs_agino_t *startino, uint16_t *allocmask) { xfs_agblock_t agbno; xfs_agblock_t mod; int offset; agbno = XFS_AGINO_TO_AGBNO(mp, *startino); mod = agbno % mp->m_sb.sb_inoalignmt; if (!mod) return; /* calculate the inode offset and align startino */ offset = mod << mp->m_sb.sb_inopblog; *startino -= offset; /* * Since startino has been aligned down, left shift allocmask such that * it continues to represent the same physical inodes relative to the * new startino. */ *allocmask <<= offset / XFS_INODES_PER_HOLEMASK_BIT; } /* * Determine whether the source inode record can merge into the target. Both * records must be sparse, the inode ranges must match and there must be no * allocation overlap between the records. */ STATIC bool __xfs_inobt_can_merge( struct xfs_inobt_rec_incore *trec, /* tgt record */ struct xfs_inobt_rec_incore *srec) /* src record */ { uint64_t talloc; uint64_t salloc; /* records must cover the same inode range */ if (trec->ir_startino != srec->ir_startino) return false; /* both records must be sparse */ if (!xfs_inobt_issparse(trec->ir_holemask) || !xfs_inobt_issparse(srec->ir_holemask)) return false; /* both records must track some inodes */ if (!trec->ir_count || !srec->ir_count) return false; /* can't exceed capacity of a full record */ if (trec->ir_count + srec->ir_count > XFS_INODES_PER_CHUNK) return false; /* verify there is no allocation overlap */ talloc = xfs_inobt_irec_to_allocmask(trec); salloc = xfs_inobt_irec_to_allocmask(srec); if (talloc & salloc) return false; return true; } /* * Merge the source inode record into the target. The caller must call * __xfs_inobt_can_merge() to ensure the merge is valid. */ STATIC void __xfs_inobt_rec_merge( struct xfs_inobt_rec_incore *trec, /* target */ struct xfs_inobt_rec_incore *srec) /* src */ { ASSERT(trec->ir_startino == srec->ir_startino); /* combine the counts */ trec->ir_count += srec->ir_count; trec->ir_freecount += srec->ir_freecount; /* * Merge the holemask and free mask. For both fields, 0 bits refer to * allocated inodes. We combine the allocated ranges with bitwise AND. */ trec->ir_holemask &= srec->ir_holemask; trec->ir_free &= srec->ir_free; } /* * Insert a new sparse inode chunk into the associated inode btree. The inode * record for the sparse chunk is pre-aligned to a startino that should match * any pre-existing sparse inode record in the tree. This allows sparse chunks * to fill over time. * * This function supports two modes of handling preexisting records depending on * the merge flag. If merge is true, the provided record is merged with the * existing record and updated in place. The merged record is returned in nrec. * If merge is false, an existing record is replaced with the provided record. * If no preexisting record exists, the provided record is always inserted. * * It is considered corruption if a merge is requested and not possible. Given * the sparse inode alignment constraints, this should never happen. */ STATIC int xfs_inobt_insert_sprec( struct xfs_mount *mp, struct xfs_trans *tp, struct xfs_buf *agbp, int btnum, struct xfs_inobt_rec_incore *nrec, /* in/out: new/merged rec. */ bool merge) /* merge or replace */ { struct xfs_btree_cur *cur; struct xfs_agi *agi = XFS_BUF_TO_AGI(agbp); xfs_agnumber_t agno = be32_to_cpu(agi->agi_seqno); int error; int i; struct xfs_inobt_rec_incore rec; cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, btnum); /* the new record is pre-aligned so we know where to look */ error = xfs_inobt_lookup(cur, nrec->ir_startino, XFS_LOOKUP_EQ, &i); if (error) goto error; /* if nothing there, insert a new record and return */ if (i == 0) { error = xfs_inobt_insert_rec(cur, nrec->ir_holemask, nrec->ir_count, nrec->ir_freecount, nrec->ir_free, &i); if (error) goto error; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error); goto out; } /* * A record exists at this startino. Merge or replace the record * depending on what we've been asked to do. */ if (merge) { error = xfs_inobt_get_rec(cur, &rec, &i); if (error) goto error; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error); XFS_WANT_CORRUPTED_GOTO(mp, rec.ir_startino == nrec->ir_startino, error); /* * This should never fail. If we have coexisting records that * cannot merge, something is seriously wrong. */ XFS_WANT_CORRUPTED_GOTO(mp, __xfs_inobt_can_merge(nrec, &rec), error); trace_xfs_irec_merge_pre(mp, agno, rec.ir_startino, rec.ir_holemask, nrec->ir_startino, nrec->ir_holemask); /* merge to nrec to output the updated record */ __xfs_inobt_rec_merge(nrec, &rec); trace_xfs_irec_merge_post(mp, agno, nrec->ir_startino, nrec->ir_holemask); error = xfs_inobt_rec_check_count(mp, nrec); if (error) goto error; } error = xfs_inobt_update(cur, nrec); if (error) goto error; out: xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); return 0; error: xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); return error; } /* * Allocate new inodes in the allocation group specified by agbp. * Return 0 for success, else error code. */ STATIC int /* error code or 0 */ xfs_ialloc_ag_alloc( xfs_trans_t *tp, /* transaction pointer */ xfs_buf_t *agbp, /* alloc group buffer */ int *alloc) { xfs_agi_t *agi; /* allocation group header */ xfs_alloc_arg_t args; /* allocation argument structure */ xfs_agnumber_t agno; int error; xfs_agino_t newino; /* new first inode's number */ xfs_agino_t newlen; /* new number of inodes */ int isaligned = 0; /* inode allocation at stripe unit */ /* boundary */ uint16_t allocmask = (uint16_t) -1; /* init. to full chunk */ struct xfs_inobt_rec_incore rec; struct xfs_perag *pag; int do_sparse = 0; memset(&args, 0, sizeof(args)); args.tp = tp; args.mp = tp->t_mountp; args.fsbno = NULLFSBLOCK; #ifdef DEBUG /* randomly do sparse inode allocations */ if (xfs_sb_version_hassparseinodes(&tp->t_mountp->m_sb) && args.mp->m_ialloc_min_blks < args.mp->m_ialloc_blks) do_sparse = prandom_u32() & 1; #endif /* * Locking will ensure that we don't have two callers in here * at one time. */ newlen = args.mp->m_ialloc_inos; if (args.mp->m_maxicount && percpu_counter_read_positive(&args.mp->m_icount) + newlen > args.mp->m_maxicount) return -ENOSPC; args.minlen = args.maxlen = args.mp->m_ialloc_blks; /* * First try to allocate inodes contiguous with the last-allocated * chunk of inodes. If the filesystem is striped, this will fill * an entire stripe unit with inodes. */ agi = XFS_BUF_TO_AGI(agbp); newino = be32_to_cpu(agi->agi_newino); agno = be32_to_cpu(agi->agi_seqno); args.agbno = XFS_AGINO_TO_AGBNO(args.mp, newino) + args.mp->m_ialloc_blks; if (do_sparse) goto sparse_alloc; if (likely(newino != NULLAGINO && (args.agbno < be32_to_cpu(agi->agi_length)))) { args.fsbno = XFS_AGB_TO_FSB(args.mp, agno, args.agbno); args.type = XFS_ALLOCTYPE_THIS_BNO; args.prod = 1; /* * We need to take into account alignment here to ensure that * we don't modify the free list if we fail to have an exact * block. If we don't have an exact match, and every oher * attempt allocation attempt fails, we'll end up cancelling * a dirty transaction and shutting down. * * For an exact allocation, alignment must be 1, * however we need to take cluster alignment into account when * fixing up the freelist. Use the minalignslop field to * indicate that extra blocks might be required for alignment, * but not to use them in the actual exact allocation. */ args.alignment = 1; args.minalignslop = xfs_ialloc_cluster_alignment(args.mp) - 1; /* Allow space for the inode btree to split. */ args.minleft = args.mp->m_in_maxlevels - 1; if ((error = xfs_alloc_vextent(&args))) return error; /* * This request might have dirtied the transaction if the AG can * satisfy the request, but the exact block was not available. * If the allocation did fail, subsequent requests will relax * the exact agbno requirement and increase the alignment * instead. It is critical that the total size of the request * (len + alignment + slop) does not increase from this point * on, so reset minalignslop to ensure it is not included in * subsequent requests. */ args.minalignslop = 0; } if (unlikely(args.fsbno == NULLFSBLOCK)) { /* * Set the alignment for the allocation. * If stripe alignment is turned on then align at stripe unit * boundary. * If the cluster size is smaller than a filesystem block * then we're doing I/O for inodes in filesystem block size * pieces, so don't need alignment anyway. */ isaligned = 0; if (args.mp->m_sinoalign) { ASSERT(!(args.mp->m_flags & XFS_MOUNT_NOALIGN)); args.alignment = args.mp->m_dalign; isaligned = 1; } else args.alignment = xfs_ialloc_cluster_alignment(args.mp); /* * Need to figure out where to allocate the inode blocks. * Ideally they should be spaced out through the a.g. * For now, just allocate blocks up front. */ args.agbno = be32_to_cpu(agi->agi_root); args.fsbno = XFS_AGB_TO_FSB(args.mp, agno, args.agbno); /* * Allocate a fixed-size extent of inodes. */ args.type = XFS_ALLOCTYPE_NEAR_BNO; args.prod = 1; /* * Allow space for the inode btree to split. */ args.minleft = args.mp->m_in_maxlevels - 1; if ((error = xfs_alloc_vextent(&args))) return error; } /* * If stripe alignment is turned on, then try again with cluster * alignment. */ if (isaligned && args.fsbno == NULLFSBLOCK) { args.type = XFS_ALLOCTYPE_NEAR_BNO; args.agbno = be32_to_cpu(agi->agi_root); args.fsbno = XFS_AGB_TO_FSB(args.mp, agno, args.agbno); args.alignment = xfs_ialloc_cluster_alignment(args.mp); if ((error = xfs_alloc_vextent(&args))) return error; } /* * Finally, try a sparse allocation if the filesystem supports it and * the sparse allocation length is smaller than a full chunk. */ if (xfs_sb_version_hassparseinodes(&args.mp->m_sb) && args.mp->m_ialloc_min_blks < args.mp->m_ialloc_blks && args.fsbno == NULLFSBLOCK) { sparse_alloc: args.type = XFS_ALLOCTYPE_NEAR_BNO; args.agbno = be32_to_cpu(agi->agi_root); args.fsbno = XFS_AGB_TO_FSB(args.mp, agno, args.agbno); args.alignment = args.mp->m_sb.sb_spino_align; args.prod = 1; args.minlen = args.mp->m_ialloc_min_blks; args.maxlen = args.minlen; /* * The inode record will be aligned to full chunk size. We must * prevent sparse allocation from AG boundaries that result in * invalid inode records, such as records that start at agbno 0 * or extend beyond the AG. * * Set min agbno to the first aligned, non-zero agbno and max to * the last aligned agbno that is at least one full chunk from * the end of the AG. */ args.min_agbno = args.mp->m_sb.sb_inoalignmt; args.max_agbno = round_down(args.mp->m_sb.sb_agblocks, args.mp->m_sb.sb_inoalignmt) - args.mp->m_ialloc_blks; error = xfs_alloc_vextent(&args); if (error) return error; newlen = args.len << args.mp->m_sb.sb_inopblog; ASSERT(newlen <= XFS_INODES_PER_CHUNK); allocmask = (1 << (newlen / XFS_INODES_PER_HOLEMASK_BIT)) - 1; } if (args.fsbno == NULLFSBLOCK) { *alloc = 0; return 0; } ASSERT(args.len == args.minlen); /* * Stamp and write the inode buffers. * * Seed the new inode cluster with a random generation number. This * prevents short-term reuse of generation numbers if a chunk is * freed and then immediately reallocated. We use random numbers * rather than a linear progression to prevent the next generation * number from being easily guessable. */ error = xfs_ialloc_inode_init(args.mp, tp, NULL, newlen, agno, args.agbno, args.len, prandom_u32()); if (error) return error; /* * Convert the results. */ newino = XFS_OFFBNO_TO_AGINO(args.mp, args.agbno, 0); if (xfs_inobt_issparse(~allocmask)) { /* * We've allocated a sparse chunk. Align the startino and mask. */ xfs_align_sparse_ino(args.mp, &newino, &allocmask); rec.ir_startino = newino; rec.ir_holemask = ~allocmask; rec.ir_count = newlen; rec.ir_freecount = newlen; rec.ir_free = XFS_INOBT_ALL_FREE; /* * Insert the sparse record into the inobt and allow for a merge * if necessary. If a merge does occur, rec is updated to the * merged record. */ error = xfs_inobt_insert_sprec(args.mp, tp, agbp, XFS_BTNUM_INO, &rec, true); if (error == -EFSCORRUPTED) { xfs_alert(args.mp, "invalid sparse inode record: ino 0x%llx holemask 0x%x count %u", XFS_AGINO_TO_INO(args.mp, agno, rec.ir_startino), rec.ir_holemask, rec.ir_count); xfs_force_shutdown(args.mp, SHUTDOWN_CORRUPT_INCORE); } if (error) return error; /* * We can't merge the part we've just allocated as for the inobt * due to finobt semantics. The original record may or may not * exist independent of whether physical inodes exist in this * sparse chunk. * * We must update the finobt record based on the inobt record. * rec contains the fully merged and up to date inobt record * from the previous call. Set merge false to replace any * existing record with this one. */ if (xfs_sb_version_hasfinobt(&args.mp->m_sb)) { error = xfs_inobt_insert_sprec(args.mp, tp, agbp, XFS_BTNUM_FINO, &rec, false); if (error) return error; } } else { /* full chunk - insert new records to both btrees */ error = xfs_inobt_insert(args.mp, tp, agbp, newino, newlen, XFS_BTNUM_INO); if (error) return error; if (xfs_sb_version_hasfinobt(&args.mp->m_sb)) { error = xfs_inobt_insert(args.mp, tp, agbp, newino, newlen, XFS_BTNUM_FINO); if (error) return error; } } /* * Update AGI counts and newino. */ be32_add_cpu(&agi->agi_count, newlen); be32_add_cpu(&agi->agi_freecount, newlen); pag = xfs_perag_get(args.mp, agno); pag->pagi_freecount += newlen; xfs_perag_put(pag); agi->agi_newino = cpu_to_be32(newino); /* * Log allocation group header fields */ xfs_ialloc_log_agi(tp, agbp, XFS_AGI_COUNT | XFS_AGI_FREECOUNT | XFS_AGI_NEWINO); /* * Modify/log superblock values for inode count and inode free count. */ xfs_trans_mod_sb(tp, XFS_TRANS_SB_ICOUNT, (long)newlen); xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, (long)newlen); *alloc = 1; return 0; } STATIC xfs_agnumber_t xfs_ialloc_next_ag( xfs_mount_t *mp) { xfs_agnumber_t agno; spin_lock(&mp->m_agirotor_lock); agno = mp->m_agirotor; if (++mp->m_agirotor >= mp->m_maxagi) mp->m_agirotor = 0; spin_unlock(&mp->m_agirotor_lock); return agno; } /* * Select an allocation group to look for a free inode in, based on the parent * inode and the mode. Return the allocation group buffer. */ STATIC xfs_agnumber_t xfs_ialloc_ag_select( xfs_trans_t *tp, /* transaction pointer */ xfs_ino_t parent, /* parent directory inode number */ umode_t mode, /* bits set to indicate file type */ int okalloc) /* ok to allocate more space */ { xfs_agnumber_t agcount; /* number of ag's in the filesystem */ xfs_agnumber_t agno; /* current ag number */ int flags; /* alloc buffer locking flags */ xfs_extlen_t ineed; /* blocks needed for inode allocation */ xfs_extlen_t longest = 0; /* longest extent available */ xfs_mount_t *mp; /* mount point structure */ int needspace; /* file mode implies space allocated */ xfs_perag_t *pag; /* per allocation group data */ xfs_agnumber_t pagno; /* parent (starting) ag number */ int error; /* * Files of these types need at least one block if length > 0 * (and they won't fit in the inode, but that's hard to figure out). */ needspace = S_ISDIR(mode) || S_ISREG(mode) || S_ISLNK(mode); mp = tp->t_mountp; agcount = mp->m_maxagi; if (S_ISDIR(mode)) pagno = xfs_ialloc_next_ag(mp); else { pagno = XFS_INO_TO_AGNO(mp, parent); if (pagno >= agcount) pagno = 0; } ASSERT(pagno < agcount); /* * Loop through allocation groups, looking for one with a little * free space in it. Note we don't look for free inodes, exactly. * Instead, we include whether there is a need to allocate inodes * to mean that blocks must be allocated for them, * if none are currently free. */ agno = pagno; flags = XFS_ALLOC_FLAG_TRYLOCK; for (;;) { pag = xfs_perag_get(mp, agno); if (!pag->pagi_inodeok) { xfs_ialloc_next_ag(mp); goto nextag; } if (!pag->pagi_init) { error = xfs_ialloc_pagi_init(mp, tp, agno); if (error) goto nextag; } if (pag->pagi_freecount) { xfs_perag_put(pag); return agno; } if (!okalloc) goto nextag; if (!pag->pagf_init) { error = xfs_alloc_pagf_init(mp, tp, agno, flags); if (error) goto nextag; } /* * Check that there is enough free space for the file plus a * chunk of inodes if we need to allocate some. If this is the * first pass across the AGs, take into account the potential * space needed for alignment of inode chunks when checking the * longest contiguous free space in the AG - this prevents us * from getting ENOSPC because we have free space larger than * m_ialloc_blks but alignment constraints prevent us from using * it. * * If we can't find an AG with space for full alignment slack to * be taken into account, we must be near ENOSPC in all AGs. * Hence we don't include alignment for the second pass and so * if we fail allocation due to alignment issues then it is most * likely a real ENOSPC condition. */ ineed = mp->m_ialloc_min_blks; if (flags && ineed > 1) ineed += xfs_ialloc_cluster_alignment(mp); longest = pag->pagf_longest; if (!longest) longest = pag->pagf_flcount > 0; if (pag->pagf_freeblks >= needspace + ineed && longest >= ineed) { xfs_perag_put(pag); return agno; } nextag: xfs_perag_put(pag); /* * No point in iterating over the rest, if we're shutting * down. */ if (XFS_FORCED_SHUTDOWN(mp)) return NULLAGNUMBER; agno++; if (agno >= agcount) agno = 0; if (agno == pagno) { if (flags == 0) return NULLAGNUMBER; flags = 0; } } } /* * Try to retrieve the next record to the left/right from the current one. */ STATIC int xfs_ialloc_next_rec( struct xfs_btree_cur *cur, xfs_inobt_rec_incore_t *rec, int *done, int left) { int error; int i; if (left) error = xfs_btree_decrement(cur, 0, &i); else error = xfs_btree_increment(cur, 0, &i); if (error) return error; *done = !i; if (i) { error = xfs_inobt_get_rec(cur, rec, &i); if (error) return error; XFS_WANT_CORRUPTED_RETURN(cur->bc_mp, i == 1); } return 0; } STATIC int xfs_ialloc_get_rec( struct xfs_btree_cur *cur, xfs_agino_t agino, xfs_inobt_rec_incore_t *rec, int *done) { int error; int i; error = xfs_inobt_lookup(cur, agino, XFS_LOOKUP_EQ, &i); if (error) return error; *done = !i; if (i) { error = xfs_inobt_get_rec(cur, rec, &i); if (error) return error; XFS_WANT_CORRUPTED_RETURN(cur->bc_mp, i == 1); } return 0; } /* * Return the offset of the first free inode in the record. If the inode chunk * is sparsely allocated, we convert the record holemask to inode granularity * and mask off the unallocated regions from the inode free mask. */ STATIC int xfs_inobt_first_free_inode( struct xfs_inobt_rec_incore *rec) { xfs_inofree_t realfree; /* if there are no holes, return the first available offset */ if (!xfs_inobt_issparse(rec->ir_holemask)) return xfs_lowbit64(rec->ir_free); realfree = xfs_inobt_irec_to_allocmask(rec); realfree &= rec->ir_free; return xfs_lowbit64(realfree); } /* * Allocate an inode using the inobt-only algorithm. */ STATIC int xfs_dialloc_ag_inobt( struct xfs_trans *tp, struct xfs_buf *agbp, xfs_ino_t parent, xfs_ino_t *inop) { struct xfs_mount *mp = tp->t_mountp; struct xfs_agi *agi = XFS_BUF_TO_AGI(agbp); xfs_agnumber_t agno = be32_to_cpu(agi->agi_seqno); xfs_agnumber_t pagno = XFS_INO_TO_AGNO(mp, parent); xfs_agino_t pagino = XFS_INO_TO_AGINO(mp, parent); struct xfs_perag *pag; struct xfs_btree_cur *cur, *tcur; struct xfs_inobt_rec_incore rec, trec; xfs_ino_t ino; int error; int offset; int i, j; pag = xfs_perag_get(mp, agno); ASSERT(pag->pagi_init); ASSERT(pag->pagi_inodeok); ASSERT(pag->pagi_freecount > 0); restart_pagno: cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_INO); /* * If pagino is 0 (this is the root inode allocation) use newino. * This must work because we've just allocated some. */ if (!pagino) pagino = be32_to_cpu(agi->agi_newino); error = xfs_check_agi_freecount(cur, agi); if (error) goto error0; /* * If in the same AG as the parent, try to get near the parent. */ if (pagno == agno) { int doneleft; /* done, to the left */ int doneright; /* done, to the right */ int searchdistance = 10; error = xfs_inobt_lookup(cur, pagino, XFS_LOOKUP_LE, &i); if (error) goto error0; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0); error = xfs_inobt_get_rec(cur, &rec, &j); if (error) goto error0; XFS_WANT_CORRUPTED_GOTO(mp, j == 1, error0); if (rec.ir_freecount > 0) { /* * Found a free inode in the same chunk * as the parent, done. */ goto alloc_inode; } /* * In the same AG as parent, but parent's chunk is full. */ /* duplicate the cursor, search left & right simultaneously */ error = xfs_btree_dup_cursor(cur, &tcur); if (error) goto error0; /* * Skip to last blocks looked up if same parent inode. */ if (pagino != NULLAGINO && pag->pagl_pagino == pagino && pag->pagl_leftrec != NULLAGINO && pag->pagl_rightrec != NULLAGINO) { error = xfs_ialloc_get_rec(tcur, pag->pagl_leftrec, &trec, &doneleft); if (error) goto error1; error = xfs_ialloc_get_rec(cur, pag->pagl_rightrec, &rec, &doneright); if (error) goto error1; } else { /* search left with tcur, back up 1 record */ error = xfs_ialloc_next_rec(tcur, &trec, &doneleft, 1); if (error) goto error1; /* search right with cur, go forward 1 record. */ error = xfs_ialloc_next_rec(cur, &rec, &doneright, 0); if (error) goto error1; } /* * Loop until we find an inode chunk with a free inode. */ while (!doneleft || !doneright) { int useleft; /* using left inode chunk this time */ if (!--searchdistance) { /* * Not in range - save last search * location and allocate a new inode */ xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR); pag->pagl_leftrec = trec.ir_startino; pag->pagl_rightrec = rec.ir_startino; pag->pagl_pagino = pagino; goto newino; } /* figure out the closer block if both are valid. */ if (!doneleft && !doneright) { useleft = pagino - (trec.ir_startino + XFS_INODES_PER_CHUNK - 1) < rec.ir_startino - pagino; } else { useleft = !doneleft; } /* free inodes to the left? */ if (useleft && trec.ir_freecount) { rec = trec; xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); cur = tcur; pag->pagl_leftrec = trec.ir_startino; pag->pagl_rightrec = rec.ir_startino; pag->pagl_pagino = pagino; goto alloc_inode; } /* free inodes to the right? */ if (!useleft && rec.ir_freecount) { xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR); pag->pagl_leftrec = trec.ir_startino; pag->pagl_rightrec = rec.ir_startino; pag->pagl_pagino = pagino; goto alloc_inode; } /* get next record to check */ if (useleft) { error = xfs_ialloc_next_rec(tcur, &trec, &doneleft, 1); } else { error = xfs_ialloc_next_rec(cur, &rec, &doneright, 0); } if (error) goto error1; } /* * We've reached the end of the btree. because * we are only searching a small chunk of the * btree each search, there is obviously free * inodes closer to the parent inode than we * are now. restart the search again. */ pag->pagl_pagino = NULLAGINO; pag->pagl_leftrec = NULLAGINO; pag->pagl_rightrec = NULLAGINO; xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR); xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); goto restart_pagno; } /* * In a different AG from the parent. * See if the most recently allocated block has any free. */ newino: if (agi->agi_newino != cpu_to_be32(NULLAGINO)) { error = xfs_inobt_lookup(cur, be32_to_cpu(agi->agi_newino), XFS_LOOKUP_EQ, &i); if (error) goto error0; if (i == 1) { error = xfs_inobt_get_rec(cur, &rec, &j); if (error) goto error0; if (j == 1 && rec.ir_freecount > 0) { /* * The last chunk allocated in the group * still has a free inode. */ goto alloc_inode; } } } /* * None left in the last group, search the whole AG */ error = xfs_inobt_lookup(cur, 0, XFS_LOOKUP_GE, &i); if (error) goto error0; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0); for (;;) { error = xfs_inobt_get_rec(cur, &rec, &i); if (error) goto error0; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0); if (rec.ir_freecount > 0) break; error = xfs_btree_increment(cur, 0, &i); if (error) goto error0; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0); } alloc_inode: offset = xfs_inobt_first_free_inode(&rec); ASSERT(offset >= 0); ASSERT(offset < XFS_INODES_PER_CHUNK); ASSERT((XFS_AGINO_TO_OFFSET(mp, rec.ir_startino) % XFS_INODES_PER_CHUNK) == 0); ino = XFS_AGINO_TO_INO(mp, agno, rec.ir_startino + offset); rec.ir_free &= ~XFS_INOBT_MASK(offset); rec.ir_freecount--; error = xfs_inobt_update(cur, &rec); if (error) goto error0; be32_add_cpu(&agi->agi_freecount, -1); xfs_ialloc_log_agi(tp, agbp, XFS_AGI_FREECOUNT); pag->pagi_freecount--; error = xfs_check_agi_freecount(cur, agi); if (error) goto error0; xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, -1); xfs_perag_put(pag); *inop = ino; return 0; error1: xfs_btree_del_cursor(tcur, XFS_BTREE_ERROR); error0: xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); xfs_perag_put(pag); return error; } /* * Use the free inode btree to allocate an inode based on distance from the * parent. Note that the provided cursor may be deleted and replaced. */ STATIC int xfs_dialloc_ag_finobt_near( xfs_agino_t pagino, struct xfs_btree_cur **ocur, struct xfs_inobt_rec_incore *rec) { struct xfs_btree_cur *lcur = *ocur; /* left search cursor */ struct xfs_btree_cur *rcur; /* right search cursor */ struct xfs_inobt_rec_incore rrec; int error; int i, j; error = xfs_inobt_lookup(lcur, pagino, XFS_LOOKUP_LE, &i); if (error) return error; if (i == 1) { error = xfs_inobt_get_rec(lcur, rec, &i); if (error) return error; XFS_WANT_CORRUPTED_RETURN(lcur->bc_mp, i == 1); /* * See if we've landed in the parent inode record. The finobt * only tracks chunks with at least one free inode, so record * existence is enough. */ if (pagino >= rec->ir_startino && pagino < (rec->ir_startino + XFS_INODES_PER_CHUNK)) return 0; } error = xfs_btree_dup_cursor(lcur, &rcur); if (error) return error; error = xfs_inobt_lookup(rcur, pagino, XFS_LOOKUP_GE, &j); if (error) goto error_rcur; if (j == 1) { error = xfs_inobt_get_rec(rcur, &rrec, &j); if (error) goto error_rcur; XFS_WANT_CORRUPTED_GOTO(lcur->bc_mp, j == 1, error_rcur); } XFS_WANT_CORRUPTED_GOTO(lcur->bc_mp, i == 1 || j == 1, error_rcur); if (i == 1 && j == 1) { /* * Both the left and right records are valid. Choose the closer * inode chunk to the target. */ if ((pagino - rec->ir_startino + XFS_INODES_PER_CHUNK - 1) > (rrec.ir_startino - pagino)) { *rec = rrec; xfs_btree_del_cursor(lcur, XFS_BTREE_NOERROR); *ocur = rcur; } else { xfs_btree_del_cursor(rcur, XFS_BTREE_NOERROR); } } else if (j == 1) { /* only the right record is valid */ *rec = rrec; xfs_btree_del_cursor(lcur, XFS_BTREE_NOERROR); *ocur = rcur; } else if (i == 1) { /* only the left record is valid */ xfs_btree_del_cursor(rcur, XFS_BTREE_NOERROR); } return 0; error_rcur: xfs_btree_del_cursor(rcur, XFS_BTREE_ERROR); return error; } /* * Use the free inode btree to find a free inode based on a newino hint. If * the hint is NULL, find the first free inode in the AG. */ STATIC int xfs_dialloc_ag_finobt_newino( struct xfs_agi *agi, struct xfs_btree_cur *cur, struct xfs_inobt_rec_incore *rec) { int error; int i; if (agi->agi_newino != cpu_to_be32(NULLAGINO)) { error = xfs_inobt_lookup(cur, be32_to_cpu(agi->agi_newino), XFS_LOOKUP_EQ, &i); if (error) return error; if (i == 1) { error = xfs_inobt_get_rec(cur, rec, &i); if (error) return error; XFS_WANT_CORRUPTED_RETURN(cur->bc_mp, i == 1); return 0; } } /* * Find the first inode available in the AG. */ error = xfs_inobt_lookup(cur, 0, XFS_LOOKUP_GE, &i); if (error) return error; XFS_WANT_CORRUPTED_RETURN(cur->bc_mp, i == 1); error = xfs_inobt_get_rec(cur, rec, &i); if (error) return error; XFS_WANT_CORRUPTED_RETURN(cur->bc_mp, i == 1); return 0; } /* * Update the inobt based on a modification made to the finobt. Also ensure that * the records from both trees are equivalent post-modification. */ STATIC int xfs_dialloc_ag_update_inobt( struct xfs_btree_cur *cur, /* inobt cursor */ struct xfs_inobt_rec_incore *frec, /* finobt record */ int offset) /* inode offset */ { struct xfs_inobt_rec_incore rec; int error; int i; error = xfs_inobt_lookup(cur, frec->ir_startino, XFS_LOOKUP_EQ, &i); if (error) return error; XFS_WANT_CORRUPTED_RETURN(cur->bc_mp, i == 1); error = xfs_inobt_get_rec(cur, &rec, &i); if (error) return error; XFS_WANT_CORRUPTED_RETURN(cur->bc_mp, i == 1); ASSERT((XFS_AGINO_TO_OFFSET(cur->bc_mp, rec.ir_startino) % XFS_INODES_PER_CHUNK) == 0); rec.ir_free &= ~XFS_INOBT_MASK(offset); rec.ir_freecount--; XFS_WANT_CORRUPTED_RETURN(cur->bc_mp, (rec.ir_free == frec->ir_free) && (rec.ir_freecount == frec->ir_freecount)); return xfs_inobt_update(cur, &rec); } /* * Allocate an inode using the free inode btree, if available. Otherwise, fall * back to the inobt search algorithm. * * The caller selected an AG for us, and made sure that free inodes are * available. */ STATIC int xfs_dialloc_ag( struct xfs_trans *tp, struct xfs_buf *agbp, xfs_ino_t parent, xfs_ino_t *inop) { struct xfs_mount *mp = tp->t_mountp; struct xfs_agi *agi = XFS_BUF_TO_AGI(agbp); xfs_agnumber_t agno = be32_to_cpu(agi->agi_seqno); xfs_agnumber_t pagno = XFS_INO_TO_AGNO(mp, parent); xfs_agino_t pagino = XFS_INO_TO_AGINO(mp, parent); struct xfs_perag *pag; struct xfs_btree_cur *cur; /* finobt cursor */ struct xfs_btree_cur *icur; /* inobt cursor */ struct xfs_inobt_rec_incore rec; xfs_ino_t ino; int error; int offset; int i; if (!xfs_sb_version_hasfinobt(&mp->m_sb)) return xfs_dialloc_ag_inobt(tp, agbp, parent, inop); pag = xfs_perag_get(mp, agno); /* * If pagino is 0 (this is the root inode allocation) use newino. * This must work because we've just allocated some. */ if (!pagino) pagino = be32_to_cpu(agi->agi_newino); cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_FINO); error = xfs_check_agi_freecount(cur, agi); if (error) goto error_cur; /* * The search algorithm depends on whether we're in the same AG as the * parent. If so, find the closest available inode to the parent. If * not, consider the agi hint or find the first free inode in the AG. */ if (agno == pagno) error = xfs_dialloc_ag_finobt_near(pagino, &cur, &rec); else error = xfs_dialloc_ag_finobt_newino(agi, cur, &rec); if (error) goto error_cur; offset = xfs_inobt_first_free_inode(&rec); ASSERT(offset >= 0); ASSERT(offset < XFS_INODES_PER_CHUNK); ASSERT((XFS_AGINO_TO_OFFSET(mp, rec.ir_startino) % XFS_INODES_PER_CHUNK) == 0); ino = XFS_AGINO_TO_INO(mp, agno, rec.ir_startino + offset); /* * Modify or remove the finobt record. */ rec.ir_free &= ~XFS_INOBT_MASK(offset); rec.ir_freecount--; if (rec.ir_freecount) error = xfs_inobt_update(cur, &rec); else error = xfs_btree_delete(cur, &i); if (error) goto error_cur; /* * The finobt has now been updated appropriately. We haven't updated the * agi and superblock yet, so we can create an inobt cursor and validate * the original freecount. If all is well, make the equivalent update to * the inobt using the finobt record and offset information. */ icur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_INO); error = xfs_check_agi_freecount(icur, agi); if (error) goto error_icur; error = xfs_dialloc_ag_update_inobt(icur, &rec, offset); if (error) goto error_icur; /* * Both trees have now been updated. We must update the perag and * superblock before we can check the freecount for each btree. */ be32_add_cpu(&agi->agi_freecount, -1); xfs_ialloc_log_agi(tp, agbp, XFS_AGI_FREECOUNT); pag->pagi_freecount--; xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, -1); error = xfs_check_agi_freecount(icur, agi); if (error) goto error_icur; error = xfs_check_agi_freecount(cur, agi); if (error) goto error_icur; xfs_btree_del_cursor(icur, XFS_BTREE_NOERROR); xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); xfs_perag_put(pag); *inop = ino; return 0; error_icur: xfs_btree_del_cursor(icur, XFS_BTREE_ERROR); error_cur: xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); xfs_perag_put(pag); return error; } /* * Allocate an inode on disk. * * Mode is used to tell whether the new inode will need space, and whether it * is a directory. * * This function is designed to be called twice if it has to do an allocation * to make more free inodes. On the first call, *IO_agbp should be set to NULL. * If an inode is available without having to performn an allocation, an inode * number is returned. In this case, *IO_agbp is set to NULL. If an allocation * needs to be done, xfs_dialloc returns the current AGI buffer in *IO_agbp. * The caller should then commit the current transaction, allocate a * new transaction, and call xfs_dialloc() again, passing in the previous value * of *IO_agbp. IO_agbp should be held across the transactions. Since the AGI * buffer is locked across the two calls, the second call is guaranteed to have * a free inode available. * * Once we successfully pick an inode its number is returned and the on-disk * data structures are updated. The inode itself is not read in, since doing so * would break ordering constraints with xfs_reclaim. */ int xfs_dialloc( struct xfs_trans *tp, xfs_ino_t parent, umode_t mode, int okalloc, struct xfs_buf **IO_agbp, xfs_ino_t *inop) { struct xfs_mount *mp = tp->t_mountp; struct xfs_buf *agbp; xfs_agnumber_t agno; int error; int ialloced; int noroom = 0; xfs_agnumber_t start_agno; struct xfs_perag *pag; if (*IO_agbp) { /* * If the caller passes in a pointer to the AGI buffer, * continue where we left off before. In this case, we * know that the allocation group has free inodes. */ agbp = *IO_agbp; goto out_alloc; } /* * We do not have an agbp, so select an initial allocation * group for inode allocation. */ start_agno = xfs_ialloc_ag_select(tp, parent, mode, okalloc); if (start_agno == NULLAGNUMBER) { *inop = NULLFSINO; return 0; } /* * If we have already hit the ceiling of inode blocks then clear * okalloc so we scan all available agi structures for a free * inode. * * Read rough value of mp->m_icount by percpu_counter_read_positive, * which will sacrifice the preciseness but improve the performance. */ if (mp->m_maxicount && percpu_counter_read_positive(&mp->m_icount) + mp->m_ialloc_inos > mp->m_maxicount) { noroom = 1; okalloc = 0; } /* * Loop until we find an allocation group that either has free inodes * or in which we can allocate some inodes. Iterate through the * allocation groups upward, wrapping at the end. */ agno = start_agno; for (;;) { pag = xfs_perag_get(mp, agno); if (!pag->pagi_inodeok) { xfs_ialloc_next_ag(mp); goto nextag; } if (!pag->pagi_init) { error = xfs_ialloc_pagi_init(mp, tp, agno); if (error) goto out_error; } /* * Do a first racy fast path check if this AG is usable. */ if (!pag->pagi_freecount && !okalloc) goto nextag; /* * Then read in the AGI buffer and recheck with the AGI buffer * lock held. */ error = xfs_ialloc_read_agi(mp, tp, agno, &agbp); if (error) goto out_error; if (pag->pagi_freecount) { xfs_perag_put(pag); goto out_alloc; } if (!okalloc) goto nextag_relse_buffer; error = xfs_ialloc_ag_alloc(tp, agbp, &ialloced); if (error) { xfs_trans_brelse(tp, agbp); if (error != -ENOSPC) goto out_error; xfs_perag_put(pag); *inop = NULLFSINO; return 0; } if (ialloced) { /* * We successfully allocated some inodes, return * the current context to the caller so that it * can commit the current transaction and call * us again where we left off. */ ASSERT(pag->pagi_freecount > 0); xfs_perag_put(pag); *IO_agbp = agbp; *inop = NULLFSINO; return 0; } nextag_relse_buffer: xfs_trans_brelse(tp, agbp); nextag: xfs_perag_put(pag); if (++agno == mp->m_sb.sb_agcount) agno = 0; if (agno == start_agno) { *inop = NULLFSINO; return noroom ? -ENOSPC : 0; } } out_alloc: *IO_agbp = NULL; return xfs_dialloc_ag(tp, agbp, parent, inop); out_error: xfs_perag_put(pag); return error; } /* * Free the blocks of an inode chunk. We must consider that the inode chunk * might be sparse and only free the regions that are allocated as part of the * chunk. */ STATIC void xfs_difree_inode_chunk( struct xfs_mount *mp, xfs_agnumber_t agno, struct xfs_inobt_rec_incore *rec, struct xfs_bmap_free *flist) { xfs_agblock_t sagbno = XFS_AGINO_TO_AGBNO(mp, rec->ir_startino); int startidx, endidx; int nextbit; xfs_agblock_t agbno; int contigblk; DECLARE_BITMAP(holemask, XFS_INOBT_HOLEMASK_BITS); if (!xfs_inobt_issparse(rec->ir_holemask)) { /* not sparse, calculate extent info directly */ xfs_bmap_add_free(XFS_AGB_TO_FSB(mp, agno, XFS_AGINO_TO_AGBNO(mp, rec->ir_startino)), mp->m_ialloc_blks, flist, mp); return; } /* holemask is only 16-bits (fits in an unsigned long) */ ASSERT(sizeof(rec->ir_holemask) <= sizeof(holemask[0])); holemask[0] = rec->ir_holemask; /* * Find contiguous ranges of zeroes (i.e., allocated regions) in the * holemask and convert the start/end index of each range to an extent. * We start with the start and end index both pointing at the first 0 in * the mask. */ startidx = endidx = find_first_zero_bit(holemask, XFS_INOBT_HOLEMASK_BITS); nextbit = startidx + 1; while (startidx < XFS_INOBT_HOLEMASK_BITS) { nextbit = find_next_zero_bit(holemask, XFS_INOBT_HOLEMASK_BITS, nextbit); /* * If the next zero bit is contiguous, update the end index of * the current range and continue. */ if (nextbit != XFS_INOBT_HOLEMASK_BITS && nextbit == endidx + 1) { endidx = nextbit; goto next; } /* * nextbit is not contiguous with the current end index. Convert * the current start/end to an extent and add it to the free * list. */ agbno = sagbno + (startidx * XFS_INODES_PER_HOLEMASK_BIT) / mp->m_sb.sb_inopblock; contigblk = ((endidx - startidx + 1) * XFS_INODES_PER_HOLEMASK_BIT) / mp->m_sb.sb_inopblock; ASSERT(agbno % mp->m_sb.sb_spino_align == 0); ASSERT(contigblk % mp->m_sb.sb_spino_align == 0); xfs_bmap_add_free(XFS_AGB_TO_FSB(mp, agno, agbno), contigblk, flist, mp); /* reset range to current bit and carry on... */ startidx = endidx = nextbit; next: nextbit++; } } STATIC int xfs_difree_inobt( struct xfs_mount *mp, struct xfs_trans *tp, struct xfs_buf *agbp, xfs_agino_t agino, struct xfs_bmap_free *flist, struct xfs_icluster *xic, struct xfs_inobt_rec_incore *orec) { struct xfs_agi *agi = XFS_BUF_TO_AGI(agbp); xfs_agnumber_t agno = be32_to_cpu(agi->agi_seqno); struct xfs_perag *pag; struct xfs_btree_cur *cur; struct xfs_inobt_rec_incore rec; int ilen; int error; int i; int off; ASSERT(agi->agi_magicnum == cpu_to_be32(XFS_AGI_MAGIC)); ASSERT(XFS_AGINO_TO_AGBNO(mp, agino) < be32_to_cpu(agi->agi_length)); /* * Initialize the cursor. */ cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_INO); error = xfs_check_agi_freecount(cur, agi); if (error) goto error0; /* * Look for the entry describing this inode. */ if ((error = xfs_inobt_lookup(cur, agino, XFS_LOOKUP_LE, &i))) { xfs_warn(mp, "%s: xfs_inobt_lookup() returned error %d.", __func__, error); goto error0; } XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0); error = xfs_inobt_get_rec(cur, &rec, &i); if (error) { xfs_warn(mp, "%s: xfs_inobt_get_rec() returned error %d.", __func__, error); goto error0; } XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0); /* * Get the offset in the inode chunk. */ off = agino - rec.ir_startino; ASSERT(off >= 0 && off < XFS_INODES_PER_CHUNK); ASSERT(!(rec.ir_free & XFS_INOBT_MASK(off))); /* * Mark the inode free & increment the count. */ rec.ir_free |= XFS_INOBT_MASK(off); rec.ir_freecount++; /* * When an inode chunk is free, it becomes eligible for removal. Don't * remove the chunk if the block size is large enough for multiple inode * chunks (that might not be free). */ if (!(mp->m_flags & XFS_MOUNT_IKEEP) && rec.ir_free == XFS_INOBT_ALL_FREE && mp->m_sb.sb_inopblock <= XFS_INODES_PER_CHUNK) { xic->deleted = 1; xic->first_ino = XFS_AGINO_TO_INO(mp, agno, rec.ir_startino); xic->alloc = xfs_inobt_irec_to_allocmask(&rec); /* * Remove the inode cluster from the AGI B+Tree, adjust the * AGI and Superblock inode counts, and mark the disk space * to be freed when the transaction is committed. */ ilen = rec.ir_freecount; be32_add_cpu(&agi->agi_count, -ilen); be32_add_cpu(&agi->agi_freecount, -(ilen - 1)); xfs_ialloc_log_agi(tp, agbp, XFS_AGI_COUNT | XFS_AGI_FREECOUNT); pag = xfs_perag_get(mp, agno); pag->pagi_freecount -= ilen - 1; xfs_perag_put(pag); xfs_trans_mod_sb(tp, XFS_TRANS_SB_ICOUNT, -ilen); xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, -(ilen - 1)); if ((error = xfs_btree_delete(cur, &i))) { xfs_warn(mp, "%s: xfs_btree_delete returned error %d.", __func__, error); goto error0; } xfs_difree_inode_chunk(mp, agno, &rec, flist); } else { xic->deleted = 0; error = xfs_inobt_update(cur, &rec); if (error) { xfs_warn(mp, "%s: xfs_inobt_update returned error %d.", __func__, error); goto error0; } /* * Change the inode free counts and log the ag/sb changes. */ be32_add_cpu(&agi->agi_freecount, 1); xfs_ialloc_log_agi(tp, agbp, XFS_AGI_FREECOUNT); pag = xfs_perag_get(mp, agno); pag->pagi_freecount++; xfs_perag_put(pag); xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, 1); } error = xfs_check_agi_freecount(cur, agi); if (error) goto error0; *orec = rec; xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); return 0; error0: xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); return error; } /* * Free an inode in the free inode btree. */ STATIC int xfs_difree_finobt( struct xfs_mount *mp, struct xfs_trans *tp, struct xfs_buf *agbp, xfs_agino_t agino, struct xfs_inobt_rec_incore *ibtrec) /* inobt record */ { struct xfs_agi *agi = XFS_BUF_TO_AGI(agbp); xfs_agnumber_t agno = be32_to_cpu(agi->agi_seqno); struct xfs_btree_cur *cur; struct xfs_inobt_rec_incore rec; int offset = agino - ibtrec->ir_startino; int error; int i; cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_FINO); error = xfs_inobt_lookup(cur, ibtrec->ir_startino, XFS_LOOKUP_EQ, &i); if (error) goto error; if (i == 0) { /* * If the record does not exist in the finobt, we must have just * freed an inode in a previously fully allocated chunk. If not, * something is out of sync. */ XFS_WANT_CORRUPTED_GOTO(mp, ibtrec->ir_freecount == 1, error); error = xfs_inobt_insert_rec(cur, ibtrec->ir_holemask, ibtrec->ir_count, ibtrec->ir_freecount, ibtrec->ir_free, &i); if (error) goto error; ASSERT(i == 1); goto out; } /* * Read and update the existing record. We could just copy the ibtrec * across here, but that would defeat the purpose of having redundant * metadata. By making the modifications independently, we can catch * corruptions that we wouldn't see if we just copied from one record * to another. */ error = xfs_inobt_get_rec(cur, &rec, &i); if (error) goto error; XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error); rec.ir_free |= XFS_INOBT_MASK(offset); rec.ir_freecount++; XFS_WANT_CORRUPTED_GOTO(mp, (rec.ir_free == ibtrec->ir_free) && (rec.ir_freecount == ibtrec->ir_freecount), error); /* * The content of inobt records should always match between the inobt * and finobt. The lifecycle of records in the finobt is different from * the inobt in that the finobt only tracks records with at least one * free inode. Hence, if all of the inodes are free and we aren't * keeping inode chunks permanently on disk, remove the record. * Otherwise, update the record with the new information. * * Note that we currently can't free chunks when the block size is large * enough for multiple chunks. Leave the finobt record to remain in sync * with the inobt. */ if (rec.ir_free == XFS_INOBT_ALL_FREE && mp->m_sb.sb_inopblock <= XFS_INODES_PER_CHUNK && !(mp->m_flags & XFS_MOUNT_IKEEP)) { error = xfs_btree_delete(cur, &i); if (error) goto error; ASSERT(i == 1); } else { error = xfs_inobt_update(cur, &rec); if (error) goto error; } out: error = xfs_check_agi_freecount(cur, agi); if (error) goto error; xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); return 0; error: xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); return error; } /* * Free disk inode. Carefully avoids touching the incore inode, all * manipulations incore are the caller's responsibility. * The on-disk inode is not changed by this operation, only the * btree (free inode mask) is changed. */ int xfs_difree( struct xfs_trans *tp, /* transaction pointer */ xfs_ino_t inode, /* inode to be freed */ struct xfs_bmap_free *flist, /* extents to free */ struct xfs_icluster *xic) /* cluster info if deleted */ { /* REFERENCED */ xfs_agblock_t agbno; /* block number containing inode */ struct xfs_buf *agbp; /* buffer for allocation group header */ xfs_agino_t agino; /* allocation group inode number */ xfs_agnumber_t agno; /* allocation group number */ int error; /* error return value */ struct xfs_mount *mp; /* mount structure for filesystem */ struct xfs_inobt_rec_incore rec;/* btree record */ mp = tp->t_mountp; /* * Break up inode number into its components. */ agno = XFS_INO_TO_AGNO(mp, inode); if (agno >= mp->m_sb.sb_agcount) { xfs_warn(mp, "%s: agno >= mp->m_sb.sb_agcount (%d >= %d).", __func__, agno, mp->m_sb.sb_agcount); ASSERT(0); return -EINVAL; } agino = XFS_INO_TO_AGINO(mp, inode); if (inode != XFS_AGINO_TO_INO(mp, agno, agino)) { xfs_warn(mp, "%s: inode != XFS_AGINO_TO_INO() (%llu != %llu).", __func__, (unsigned long long)inode, (unsigned long long)XFS_AGINO_TO_INO(mp, agno, agino)); ASSERT(0); return -EINVAL; } agbno = XFS_AGINO_TO_AGBNO(mp, agino); if (agbno >= mp->m_sb.sb_agblocks) { xfs_warn(mp, "%s: agbno >= mp->m_sb.sb_agblocks (%d >= %d).", __func__, agbno, mp->m_sb.sb_agblocks); ASSERT(0); return -EINVAL; } /* * Get the allocation group header. */ error = xfs_ialloc_read_agi(mp, tp, agno, &agbp); if (error) { xfs_warn(mp, "%s: xfs_ialloc_read_agi() returned error %d.", __func__, error); return error; } /* * Fix up the inode allocation btree. */ error = xfs_difree_inobt(mp, tp, agbp, agino, flist, xic, &rec); if (error) goto error0; /* * Fix up the free inode btree. */ if (xfs_sb_version_hasfinobt(&mp->m_sb)) { error = xfs_difree_finobt(mp, tp, agbp, agino, &rec); if (error) goto error0; } return 0; error0: return error; } STATIC int xfs_imap_lookup( struct xfs_mount *mp, struct xfs_trans *tp, xfs_agnumber_t agno, xfs_agino_t agino, xfs_agblock_t agbno, xfs_agblock_t *chunk_agbno, xfs_agblock_t *offset_agbno, int flags) { struct xfs_inobt_rec_incore rec; struct xfs_btree_cur *cur; struct xfs_buf *agbp; int error; int i; error = xfs_ialloc_read_agi(mp, tp, agno, &agbp); if (error) { xfs_alert(mp, "%s: xfs_ialloc_read_agi() returned error %d, agno %d", __func__, error, agno); return error; } /* * Lookup the inode record for the given agino. If the record cannot be * found, then it's an invalid inode number and we should abort. Once * we have a record, we need to ensure it contains the inode number * we are looking up. */ cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_INO); error = xfs_inobt_lookup(cur, agino, XFS_LOOKUP_LE, &i); if (!error) { if (i) error = xfs_inobt_get_rec(cur, &rec, &i); if (!error && i == 0) error = -EINVAL; } xfs_trans_brelse(tp, agbp); xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); if (error) return error; /* check that the returned record contains the required inode */ if (rec.ir_startino > agino || rec.ir_startino + mp->m_ialloc_inos <= agino) return -EINVAL; /* for untrusted inodes check it is allocated first */ if ((flags & XFS_IGET_UNTRUSTED) && (rec.ir_free & XFS_INOBT_MASK(agino - rec.ir_startino))) return -EINVAL; *chunk_agbno = XFS_AGINO_TO_AGBNO(mp, rec.ir_startino); *offset_agbno = agbno - *chunk_agbno; return 0; } /* * Return the location of the inode in imap, for mapping it into a buffer. */ int xfs_imap( xfs_mount_t *mp, /* file system mount structure */ xfs_trans_t *tp, /* transaction pointer */ xfs_ino_t ino, /* inode to locate */ struct xfs_imap *imap, /* location map structure */ uint flags) /* flags for inode btree lookup */ { xfs_agblock_t agbno; /* block number of inode in the alloc group */ xfs_agino_t agino; /* inode number within alloc group */ xfs_agnumber_t agno; /* allocation group number */ int blks_per_cluster; /* num blocks per inode cluster */ xfs_agblock_t chunk_agbno; /* first block in inode chunk */ xfs_agblock_t cluster_agbno; /* first block in inode cluster */ int error; /* error code */ int offset; /* index of inode in its buffer */ xfs_agblock_t offset_agbno; /* blks from chunk start to inode */ ASSERT(ino != NULLFSINO); /* * Split up the inode number into its parts. */ agno = XFS_INO_TO_AGNO(mp, ino); agino = XFS_INO_TO_AGINO(mp, ino); agbno = XFS_AGINO_TO_AGBNO(mp, agino); if (agno >= mp->m_sb.sb_agcount || agbno >= mp->m_sb.sb_agblocks || ino != XFS_AGINO_TO_INO(mp, agno, agino)) { #ifdef DEBUG /* * Don't output diagnostic information for untrusted inodes * as they can be invalid without implying corruption. */ if (flags & XFS_IGET_UNTRUSTED) return -EINVAL; if (agno >= mp->m_sb.sb_agcount) { xfs_alert(mp, "%s: agno (%d) >= mp->m_sb.sb_agcount (%d)", __func__, agno, mp->m_sb.sb_agcount); } if (agbno >= mp->m_sb.sb_agblocks) { xfs_alert(mp, "%s: agbno (0x%llx) >= mp->m_sb.sb_agblocks (0x%lx)", __func__, (unsigned long long)agbno, (unsigned long)mp->m_sb.sb_agblocks); } if (ino != XFS_AGINO_TO_INO(mp, agno, agino)) { xfs_alert(mp, "%s: ino (0x%llx) != XFS_AGINO_TO_INO() (0x%llx)", __func__, ino, XFS_AGINO_TO_INO(mp, agno, agino)); } xfs_stack_trace(); #endif /* DEBUG */ return -EINVAL; } blks_per_cluster = xfs_icluster_size_fsb(mp); /* * For bulkstat and handle lookups, we have an untrusted inode number * that we have to verify is valid. We cannot do this just by reading * the inode buffer as it may have been unlinked and removed leaving * inodes in stale state on disk. Hence we have to do a btree lookup * in all cases where an untrusted inode number is passed. */ if (flags & XFS_IGET_UNTRUSTED) { error = xfs_imap_lookup(mp, tp, agno, agino, agbno, &chunk_agbno, &offset_agbno, flags); if (error) return error; goto out_map; } /* * If the inode cluster size is the same as the blocksize or * smaller we get to the buffer by simple arithmetics. */ if (blks_per_cluster == 1) { offset = XFS_INO_TO_OFFSET(mp, ino); ASSERT(offset < mp->m_sb.sb_inopblock); imap->im_blkno = XFS_AGB_TO_DADDR(mp, agno, agbno); imap->im_len = XFS_FSB_TO_BB(mp, 1); imap->im_boffset = (unsigned short)(offset << mp->m_sb.sb_inodelog); return 0; } /* * If the inode chunks are aligned then use simple maths to * find the location. Otherwise we have to do a btree * lookup to find the location. */ if (mp->m_inoalign_mask) { offset_agbno = agbno & mp->m_inoalign_mask; chunk_agbno = agbno - offset_agbno; } else { error = xfs_imap_lookup(mp, tp, agno, agino, agbno, &chunk_agbno, &offset_agbno, flags); if (error) return error; } out_map: ASSERT(agbno >= chunk_agbno); cluster_agbno = chunk_agbno + ((offset_agbno / blks_per_cluster) * blks_per_cluster); offset = ((agbno - cluster_agbno) * mp->m_sb.sb_inopblock) + XFS_INO_TO_OFFSET(mp, ino); imap->im_blkno = XFS_AGB_TO_DADDR(mp, agno, cluster_agbno); imap->im_len = XFS_FSB_TO_BB(mp, blks_per_cluster); imap->im_boffset = (unsigned short)(offset << mp->m_sb.sb_inodelog); /* * If the inode number maps to a block outside the bounds * of the file system then return NULL rather than calling * read_buf and panicing when we get an error from the * driver. */ if ((imap->im_blkno + imap->im_len) > XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks)) { xfs_alert(mp, "%s: (im_blkno (0x%llx) + im_len (0x%llx)) > sb_dblocks (0x%llx)", __func__, (unsigned long long) imap->im_blkno, (unsigned long long) imap->im_len, XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks)); return -EINVAL; } return 0; } /* * Compute and fill in value of m_in_maxlevels. */ void xfs_ialloc_compute_maxlevels( xfs_mount_t *mp) /* file system mount structure */ { int level; uint maxblocks; uint maxleafents; int minleafrecs; int minnoderecs; maxleafents = (1LL << XFS_INO_AGINO_BITS(mp)) >> XFS_INODES_PER_CHUNK_LOG; minleafrecs = mp->m_alloc_mnr[0]; minnoderecs = mp->m_alloc_mnr[1]; maxblocks = (maxleafents + minleafrecs - 1) / minleafrecs; for (level = 1; maxblocks > 1; level++) maxblocks = (maxblocks + minnoderecs - 1) / minnoderecs; mp->m_in_maxlevels = level; } /* * Log specified fields for the ag hdr (inode section). The growth of the agi * structure over time requires that we interpret the buffer as two logical * regions delineated by the end of the unlinked list. This is due to the size * of the hash table and its location in the middle of the agi. * * For example, a request to log a field before agi_unlinked and a field after * agi_unlinked could cause us to log the entire hash table and use an excessive * amount of log space. To avoid this behavior, log the region up through * agi_unlinked in one call and the region after agi_unlinked through the end of * the structure in another. */ void xfs_ialloc_log_agi( xfs_trans_t *tp, /* transaction pointer */ xfs_buf_t *bp, /* allocation group header buffer */ int fields) /* bitmask of fields to log */ { int first; /* first byte number */ int last; /* last byte number */ static const short offsets[] = { /* field starting offsets */ /* keep in sync with bit definitions */ offsetof(xfs_agi_t, agi_magicnum), offsetof(xfs_agi_t, agi_versionnum), offsetof(xfs_agi_t, agi_seqno), offsetof(xfs_agi_t, agi_length), offsetof(xfs_agi_t, agi_count), offsetof(xfs_agi_t, agi_root), offsetof(xfs_agi_t, agi_level), offsetof(xfs_agi_t, agi_freecount), offsetof(xfs_agi_t, agi_newino), offsetof(xfs_agi_t, agi_dirino), offsetof(xfs_agi_t, agi_unlinked), offsetof(xfs_agi_t, agi_free_root), offsetof(xfs_agi_t, agi_free_level), sizeof(xfs_agi_t) }; #ifdef DEBUG xfs_agi_t *agi; /* allocation group header */ agi = XFS_BUF_TO_AGI(bp); ASSERT(agi->agi_magicnum == cpu_to_be32(XFS_AGI_MAGIC)); #endif xfs_trans_buf_set_type(tp, bp, XFS_BLFT_AGI_BUF); /* * Compute byte offsets for the first and last fields in the first * region and log the agi buffer. This only logs up through * agi_unlinked. */ if (fields & XFS_AGI_ALL_BITS_R1) { xfs_btree_offsets(fields, offsets, XFS_AGI_NUM_BITS_R1, &first, &last); xfs_trans_log_buf(tp, bp, first, last); } /* * Mask off the bits in the first region and calculate the first and * last field offsets for any bits in the second region. */ fields &= ~XFS_AGI_ALL_BITS_R1; if (fields) { xfs_btree_offsets(fields, offsets, XFS_AGI_NUM_BITS_R2, &first, &last); xfs_trans_log_buf(tp, bp, first, last); } } #ifdef DEBUG STATIC void xfs_check_agi_unlinked( struct xfs_agi *agi) { int i; for (i = 0; i < XFS_AGI_UNLINKED_BUCKETS; i++) ASSERT(agi->agi_unlinked[i]); } #else #define xfs_check_agi_unlinked(agi) #endif static bool xfs_agi_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_target->bt_mount; struct xfs_agi *agi = XFS_BUF_TO_AGI(bp); if (xfs_sb_version_hascrc(&mp->m_sb) && !uuid_equal(&agi->agi_uuid, &mp->m_sb.sb_meta_uuid)) return false; /* * Validate the magic number of the agi block. */ if (agi->agi_magicnum != cpu_to_be32(XFS_AGI_MAGIC)) return false; if (!XFS_AGI_GOOD_VERSION(be32_to_cpu(agi->agi_versionnum))) return false; if (be32_to_cpu(agi->agi_level) > XFS_BTREE_MAXLEVELS) return false; /* * during growfs operations, the perag is not fully initialised, * so we can't use it for any useful checking. growfs ensures we can't * use it by using uncached buffers that don't have the perag attached * so we can detect and avoid this problem. */ if (bp->b_pag && be32_to_cpu(agi->agi_seqno) != bp->b_pag->pag_agno) return false; xfs_check_agi_unlinked(agi); return true; } static void xfs_agi_read_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_target->bt_mount; if (xfs_sb_version_hascrc(&mp->m_sb) && !xfs_buf_verify_cksum(bp, XFS_AGI_CRC_OFF)) xfs_buf_ioerror(bp, -EFSBADCRC); else if (XFS_TEST_ERROR(!xfs_agi_verify(bp), mp, XFS_ERRTAG_IALLOC_READ_AGI, XFS_RANDOM_IALLOC_READ_AGI)) xfs_buf_ioerror(bp, -EFSCORRUPTED); if (bp->b_error) xfs_verifier_error(bp); } static void xfs_agi_write_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_target->bt_mount; struct xfs_buf_log_item *bip = bp->b_fspriv; if (!xfs_agi_verify(bp)) { xfs_buf_ioerror(bp, -EFSCORRUPTED); xfs_verifier_error(bp); return; } if (!xfs_sb_version_hascrc(&mp->m_sb)) return; if (bip) XFS_BUF_TO_AGI(bp)->agi_lsn = cpu_to_be64(bip->bli_item.li_lsn); xfs_buf_update_cksum(bp, XFS_AGI_CRC_OFF); } const struct xfs_buf_ops xfs_agi_buf_ops = { .verify_read = xfs_agi_read_verify, .verify_write = xfs_agi_write_verify, }; /* * Read in the allocation group header (inode allocation section) */ int xfs_read_agi( struct xfs_mount *mp, /* file system mount structure */ struct xfs_trans *tp, /* transaction pointer */ xfs_agnumber_t agno, /* allocation group number */ struct xfs_buf **bpp) /* allocation group hdr buf */ { int error; trace_xfs_read_agi(mp, agno); ASSERT(agno != NULLAGNUMBER); error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR(mp)), XFS_FSS_TO_BB(mp, 1), 0, bpp, &xfs_agi_buf_ops); if (error) return error; xfs_buf_set_ref(*bpp, XFS_AGI_REF); return 0; } int xfs_ialloc_read_agi( struct xfs_mount *mp, /* file system mount structure */ struct xfs_trans *tp, /* transaction pointer */ xfs_agnumber_t agno, /* allocation group number */ struct xfs_buf **bpp) /* allocation group hdr buf */ { struct xfs_agi *agi; /* allocation group header */ struct xfs_perag *pag; /* per allocation group data */ int error; trace_xfs_ialloc_read_agi(mp, agno); error = xfs_read_agi(mp, tp, agno, bpp); if (error) return error; agi = XFS_BUF_TO_AGI(*bpp); pag = xfs_perag_get(mp, agno); if (!pag->pagi_init) { pag->pagi_freecount = be32_to_cpu(agi->agi_freecount); pag->pagi_count = be32_to_cpu(agi->agi_count); pag->pagi_init = 1; } /* * It's possible for these to be out of sync if * we are in the middle of a forced shutdown. */ ASSERT(pag->pagi_freecount == be32_to_cpu(agi->agi_freecount) || XFS_FORCED_SHUTDOWN(mp)); xfs_perag_put(pag); return 0; } /* * Read in the agi to initialise the per-ag data in the mount structure */ int xfs_ialloc_pagi_init( xfs_mount_t *mp, /* file system mount structure */ xfs_trans_t *tp, /* transaction pointer */ xfs_agnumber_t agno) /* allocation group number */ { xfs_buf_t *bp = NULL; int error; error = xfs_ialloc_read_agi(mp, tp, agno, &bp); if (error) return error; if (bp) xfs_trans_brelse(tp, bp); return 0; } partclone-0.2.86/src/xfs/xfs_ialloc.h000066400000000000000000000127131262102574200174660ustar00rootroot00000000000000/* * Copyright (c) 2000,2005 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __XFS_IALLOC_H__ #define __XFS_IALLOC_H__ struct xfs_buf; struct xfs_dinode; struct xfs_imap; struct xfs_mount; struct xfs_trans; struct xfs_btree_cur; /* Move inodes in clusters of this size */ #define XFS_INODE_BIG_CLUSTER_SIZE 8192 struct xfs_icluster { bool deleted; /* record is deleted */ xfs_ino_t first_ino; /* first inode number */ uint64_t alloc; /* inode phys. allocation bitmap for * sparse chunks */ }; /* Calculate and return the number of filesystem blocks per inode cluster */ static inline int xfs_icluster_size_fsb( struct xfs_mount *mp) { if (mp->m_sb.sb_blocksize >= mp->m_inode_cluster_size) return 1; return mp->m_inode_cluster_size >> mp->m_sb.sb_blocklog; } /* * Make an inode pointer out of the buffer/offset. */ static inline struct xfs_dinode * xfs_make_iptr(struct xfs_mount *mp, struct xfs_buf *b, int o) { return xfs_buf_offset(b, o << (mp)->m_sb.sb_inodelog); } /* * Allocate an inode on disk. * Mode is used to tell whether the new inode will need space, and whether * it is a directory. * * To work within the constraint of one allocation per transaction, * xfs_dialloc() is designed to be called twice if it has to do an * allocation to make more free inodes. If an inode is * available without an allocation, agbp would be set to the current * agbp and alloc_done set to false. * If an allocation needed to be done, agbp would be set to the * inode header of the allocation group and alloc_done set to true. * The caller should then commit the current transaction and allocate a new * transaction. xfs_dialloc() should then be called again with * the agbp value returned from the previous call. * * Once we successfully pick an inode its number is returned and the * on-disk data structures are updated. The inode itself is not read * in, since doing so would break ordering constraints with xfs_reclaim. * * *agbp should be set to NULL on the first call, *alloc_done set to FALSE. */ int /* error */ xfs_dialloc( struct xfs_trans *tp, /* transaction pointer */ xfs_ino_t parent, /* parent inode (directory) */ umode_t mode, /* mode bits for new inode */ int okalloc, /* ok to allocate more space */ struct xfs_buf **agbp, /* buf for a.g. inode header */ xfs_ino_t *inop); /* inode number allocated */ /* * Free disk inode. Carefully avoids touching the incore inode, all * manipulations incore are the caller's responsibility. * The on-disk inode is not changed by this operation, only the * btree (free inode mask) is changed. */ int /* error */ xfs_difree( struct xfs_trans *tp, /* transaction pointer */ xfs_ino_t inode, /* inode to be freed */ struct xfs_bmap_free *flist, /* extents to free */ struct xfs_icluster *ifree); /* cluster info if deleted */ /* * Return the location of the inode in imap, for mapping it into a buffer. */ int xfs_imap( struct xfs_mount *mp, /* file system mount structure */ struct xfs_trans *tp, /* transaction pointer */ xfs_ino_t ino, /* inode to locate */ struct xfs_imap *imap, /* location map structure */ uint flags); /* flags for inode btree lookup */ /* * Compute and fill in value of m_in_maxlevels. */ void xfs_ialloc_compute_maxlevels( struct xfs_mount *mp); /* file system mount structure */ /* * Log specified fields for the ag hdr (inode section) */ void xfs_ialloc_log_agi( struct xfs_trans *tp, /* transaction pointer */ struct xfs_buf *bp, /* allocation group header buffer */ int fields); /* bitmask of fields to log */ /* * Read in the allocation group header (inode allocation section) */ int /* error */ xfs_ialloc_read_agi( struct xfs_mount *mp, /* file system mount structure */ struct xfs_trans *tp, /* transaction pointer */ xfs_agnumber_t agno, /* allocation group number */ struct xfs_buf **bpp); /* allocation group hdr buf */ /* * Read in the allocation group header to initialise the per-ag data * in the mount structure */ int xfs_ialloc_pagi_init( struct xfs_mount *mp, /* file system mount structure */ struct xfs_trans *tp, /* transaction pointer */ xfs_agnumber_t agno); /* allocation group number */ /* * Lookup a record by ino in the btree given by cur. */ int xfs_inobt_lookup(struct xfs_btree_cur *cur, xfs_agino_t ino, xfs_lookup_t dir, int *stat); /* * Get the data from the pointed-to record. */ int xfs_inobt_get_rec(struct xfs_btree_cur *cur, xfs_inobt_rec_incore_t *rec, int *stat); /* * Inode chunk initialisation routine */ int xfs_ialloc_inode_init(struct xfs_mount *mp, struct xfs_trans *tp, struct list_head *buffer_list, int icount, xfs_agnumber_t agno, xfs_agblock_t agbno, xfs_agblock_t length, unsigned int gen); int xfs_read_agi(struct xfs_mount *mp, struct xfs_trans *tp, xfs_agnumber_t agno, struct xfs_buf **bpp); #endif /* __XFS_IALLOC_H__ */ partclone-0.2.86/src/xfs/xfs_ialloc_btree.c000066400000000000000000000317711262102574200206470ustar00rootroot00000000000000/* * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_bit.h" #include "xfs_mount.h" #include "xfs_inode.h" #include "xfs_btree.h" #include "xfs_ialloc.h" #include "xfs_ialloc_btree.h" #include "xfs_alloc.h" #include "xfs_trace.h" #include "xfs_cksum.h" #include "xfs_trans.h" STATIC int xfs_inobt_get_minrecs( struct xfs_btree_cur *cur, int level) { return cur->bc_mp->m_inobt_mnr[level != 0]; } STATIC struct xfs_btree_cur * xfs_inobt_dup_cursor( struct xfs_btree_cur *cur) { return xfs_inobt_init_cursor(cur->bc_mp, cur->bc_tp, cur->bc_private.a.agbp, cur->bc_private.a.agno, cur->bc_btnum); } STATIC void xfs_inobt_set_root( struct xfs_btree_cur *cur, union xfs_btree_ptr *nptr, int inc) /* level change */ { struct xfs_buf *agbp = cur->bc_private.a.agbp; struct xfs_agi *agi = XFS_BUF_TO_AGI(agbp); agi->agi_root = nptr->s; be32_add_cpu(&agi->agi_level, inc); xfs_ialloc_log_agi(cur->bc_tp, agbp, XFS_AGI_ROOT | XFS_AGI_LEVEL); } STATIC void xfs_finobt_set_root( struct xfs_btree_cur *cur, union xfs_btree_ptr *nptr, int inc) /* level change */ { struct xfs_buf *agbp = cur->bc_private.a.agbp; struct xfs_agi *agi = XFS_BUF_TO_AGI(agbp); agi->agi_free_root = nptr->s; be32_add_cpu(&agi->agi_free_level, inc); xfs_ialloc_log_agi(cur->bc_tp, agbp, XFS_AGI_FREE_ROOT | XFS_AGI_FREE_LEVEL); } STATIC int xfs_inobt_alloc_block( struct xfs_btree_cur *cur, union xfs_btree_ptr *start, union xfs_btree_ptr *new, int *stat) { xfs_alloc_arg_t args; /* block allocation args */ int error; /* error return value */ xfs_agblock_t sbno = be32_to_cpu(start->s); XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY); memset(&args, 0, sizeof(args)); args.tp = cur->bc_tp; args.mp = cur->bc_mp; args.fsbno = XFS_AGB_TO_FSB(args.mp, cur->bc_private.a.agno, sbno); args.minlen = 1; args.maxlen = 1; args.prod = 1; args.type = XFS_ALLOCTYPE_NEAR_BNO; error = xfs_alloc_vextent(&args); if (error) { XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR); return error; } if (args.fsbno == NULLFSBLOCK) { XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); *stat = 0; return 0; } ASSERT(args.len == 1); XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); new->s = cpu_to_be32(XFS_FSB_TO_AGBNO(args.mp, args.fsbno)); *stat = 1; return 0; } STATIC int xfs_inobt_free_block( struct xfs_btree_cur *cur, struct xfs_buf *bp) { xfs_fsblock_t fsbno; int error; fsbno = XFS_DADDR_TO_FSB(cur->bc_mp, XFS_BUF_ADDR(bp)); error = xfs_free_extent(cur->bc_tp, fsbno, 1); if (error) return error; xfs_trans_binval(cur->bc_tp, bp); return error; } STATIC int xfs_inobt_get_maxrecs( struct xfs_btree_cur *cur, int level) { return cur->bc_mp->m_inobt_mxr[level != 0]; } STATIC void xfs_inobt_init_key_from_rec( union xfs_btree_key *key, union xfs_btree_rec *rec) { key->inobt.ir_startino = rec->inobt.ir_startino; } STATIC void xfs_inobt_init_rec_from_key( union xfs_btree_key *key, union xfs_btree_rec *rec) { rec->inobt.ir_startino = key->inobt.ir_startino; } STATIC void xfs_inobt_init_rec_from_cur( struct xfs_btree_cur *cur, union xfs_btree_rec *rec) { rec->inobt.ir_startino = cpu_to_be32(cur->bc_rec.i.ir_startino); if (xfs_sb_version_hassparseinodes(&cur->bc_mp->m_sb)) { rec->inobt.ir_u.sp.ir_holemask = cpu_to_be16(cur->bc_rec.i.ir_holemask); rec->inobt.ir_u.sp.ir_count = cur->bc_rec.i.ir_count; rec->inobt.ir_u.sp.ir_freecount = cur->bc_rec.i.ir_freecount; } else { /* ir_holemask/ir_count not supported on-disk */ rec->inobt.ir_u.f.ir_freecount = cpu_to_be32(cur->bc_rec.i.ir_freecount); } rec->inobt.ir_free = cpu_to_be64(cur->bc_rec.i.ir_free); } /* * initial value of ptr for lookup */ STATIC void xfs_inobt_init_ptr_from_cur( struct xfs_btree_cur *cur, union xfs_btree_ptr *ptr) { struct xfs_agi *agi = XFS_BUF_TO_AGI(cur->bc_private.a.agbp); ASSERT(cur->bc_private.a.agno == be32_to_cpu(agi->agi_seqno)); ptr->s = agi->agi_root; } STATIC void xfs_finobt_init_ptr_from_cur( struct xfs_btree_cur *cur, union xfs_btree_ptr *ptr) { struct xfs_agi *agi = XFS_BUF_TO_AGI(cur->bc_private.a.agbp); ASSERT(cur->bc_private.a.agno == be32_to_cpu(agi->agi_seqno)); ptr->s = agi->agi_free_root; } STATIC __int64_t xfs_inobt_key_diff( struct xfs_btree_cur *cur, union xfs_btree_key *key) { return (__int64_t)be32_to_cpu(key->inobt.ir_startino) - cur->bc_rec.i.ir_startino; } static int xfs_inobt_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_target->bt_mount; struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); struct xfs_perag *pag = bp->b_pag; unsigned int level; /* * During growfs operations, we can't verify the exact owner as the * perag is not fully initialised and hence not attached to the buffer. * * Similarly, during log recovery we will have a perag structure * attached, but the agi information will not yet have been initialised * from the on disk AGI. We don't currently use any of this information, * but beware of the landmine (i.e. need to check pag->pagi_init) if we * ever do. */ switch (block->bb_magic) { case cpu_to_be32(XFS_IBT_CRC_MAGIC): case cpu_to_be32(XFS_FIBT_CRC_MAGIC): if (!xfs_sb_version_hascrc(&mp->m_sb)) return false; if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_meta_uuid)) return false; if (block->bb_u.s.bb_blkno != cpu_to_be64(bp->b_bn)) return false; if (pag && be32_to_cpu(block->bb_u.s.bb_owner) != pag->pag_agno) return false; /* fall through */ case cpu_to_be32(XFS_IBT_MAGIC): case cpu_to_be32(XFS_FIBT_MAGIC): break; default: return 0; } /* numrecs and level verification */ level = be16_to_cpu(block->bb_level); if (level >= mp->m_in_maxlevels) return false; if (be16_to_cpu(block->bb_numrecs) > mp->m_inobt_mxr[level != 0]) return false; /* sibling pointer verification */ if (!block->bb_u.s.bb_leftsib || (be32_to_cpu(block->bb_u.s.bb_leftsib) >= mp->m_sb.sb_agblocks && block->bb_u.s.bb_leftsib != cpu_to_be32(NULLAGBLOCK))) return false; if (!block->bb_u.s.bb_rightsib || (be32_to_cpu(block->bb_u.s.bb_rightsib) >= mp->m_sb.sb_agblocks && block->bb_u.s.bb_rightsib != cpu_to_be32(NULLAGBLOCK))) return false; return true; } static void xfs_inobt_read_verify( struct xfs_buf *bp) { if (!xfs_btree_sblock_verify_crc(bp)) xfs_buf_ioerror(bp, -EFSBADCRC); else if (!xfs_inobt_verify(bp)) xfs_buf_ioerror(bp, -EFSCORRUPTED); if (bp->b_error) { trace_xfs_btree_corrupt(bp, _RET_IP_); xfs_verifier_error(bp); } } static void xfs_inobt_write_verify( struct xfs_buf *bp) { if (!xfs_inobt_verify(bp)) { trace_xfs_btree_corrupt(bp, _RET_IP_); xfs_buf_ioerror(bp, -EFSCORRUPTED); xfs_verifier_error(bp); return; } xfs_btree_sblock_calc_crc(bp); } const struct xfs_buf_ops xfs_inobt_buf_ops = { .verify_read = xfs_inobt_read_verify, .verify_write = xfs_inobt_write_verify, }; #if defined(DEBUG) || defined(XFS_WARN) STATIC int xfs_inobt_keys_inorder( struct xfs_btree_cur *cur, union xfs_btree_key *k1, union xfs_btree_key *k2) { return be32_to_cpu(k1->inobt.ir_startino) < be32_to_cpu(k2->inobt.ir_startino); } STATIC int xfs_inobt_recs_inorder( struct xfs_btree_cur *cur, union xfs_btree_rec *r1, union xfs_btree_rec *r2) { return be32_to_cpu(r1->inobt.ir_startino) + XFS_INODES_PER_CHUNK <= be32_to_cpu(r2->inobt.ir_startino); } #endif /* DEBUG */ static const struct xfs_btree_ops xfs_inobt_ops = { .rec_len = sizeof(xfs_inobt_rec_t), .key_len = sizeof(xfs_inobt_key_t), .dup_cursor = xfs_inobt_dup_cursor, .set_root = xfs_inobt_set_root, .alloc_block = xfs_inobt_alloc_block, .free_block = xfs_inobt_free_block, .get_minrecs = xfs_inobt_get_minrecs, .get_maxrecs = xfs_inobt_get_maxrecs, .init_key_from_rec = xfs_inobt_init_key_from_rec, .init_rec_from_key = xfs_inobt_init_rec_from_key, .init_rec_from_cur = xfs_inobt_init_rec_from_cur, .init_ptr_from_cur = xfs_inobt_init_ptr_from_cur, .key_diff = xfs_inobt_key_diff, .buf_ops = &xfs_inobt_buf_ops, #if defined(DEBUG) || defined(XFS_WARN) .keys_inorder = xfs_inobt_keys_inorder, .recs_inorder = xfs_inobt_recs_inorder, #endif }; static const struct xfs_btree_ops xfs_finobt_ops = { .rec_len = sizeof(xfs_inobt_rec_t), .key_len = sizeof(xfs_inobt_key_t), .dup_cursor = xfs_inobt_dup_cursor, .set_root = xfs_finobt_set_root, .alloc_block = xfs_inobt_alloc_block, .free_block = xfs_inobt_free_block, .get_minrecs = xfs_inobt_get_minrecs, .get_maxrecs = xfs_inobt_get_maxrecs, .init_key_from_rec = xfs_inobt_init_key_from_rec, .init_rec_from_key = xfs_inobt_init_rec_from_key, .init_rec_from_cur = xfs_inobt_init_rec_from_cur, .init_ptr_from_cur = xfs_finobt_init_ptr_from_cur, .key_diff = xfs_inobt_key_diff, .buf_ops = &xfs_inobt_buf_ops, #if defined(DEBUG) || defined(XFS_WARN) .keys_inorder = xfs_inobt_keys_inorder, .recs_inorder = xfs_inobt_recs_inorder, #endif }; /* * Allocate a new inode btree cursor. */ struct xfs_btree_cur * /* new inode btree cursor */ xfs_inobt_init_cursor( struct xfs_mount *mp, /* file system mount point */ struct xfs_trans *tp, /* transaction pointer */ struct xfs_buf *agbp, /* buffer for agi structure */ xfs_agnumber_t agno, /* allocation group number */ xfs_btnum_t btnum) /* ialloc or free ino btree */ { struct xfs_agi *agi = XFS_BUF_TO_AGI(agbp); struct xfs_btree_cur *cur; cur = kmem_zone_zalloc(xfs_btree_cur_zone, KM_SLEEP); cur->bc_tp = tp; cur->bc_mp = mp; cur->bc_btnum = btnum; if (btnum == XFS_BTNUM_INO) { cur->bc_nlevels = be32_to_cpu(agi->agi_level); cur->bc_ops = &xfs_inobt_ops; } else { cur->bc_nlevels = be32_to_cpu(agi->agi_free_level); cur->bc_ops = &xfs_finobt_ops; } cur->bc_blocklog = mp->m_sb.sb_blocklog; if (xfs_sb_version_hascrc(&mp->m_sb)) cur->bc_flags |= XFS_BTREE_CRC_BLOCKS; cur->bc_private.a.agbp = agbp; cur->bc_private.a.agno = agno; return cur; } /* * Calculate number of records in an inobt btree block. */ int xfs_inobt_maxrecs( struct xfs_mount *mp, int blocklen, int leaf) { blocklen -= XFS_INOBT_BLOCK_LEN(mp); if (leaf) return blocklen / sizeof(xfs_inobt_rec_t); return blocklen / (sizeof(xfs_inobt_key_t) + sizeof(xfs_inobt_ptr_t)); } /* * Convert the inode record holemask to an inode allocation bitmap. The inode * allocation bitmap is inode granularity and specifies whether an inode is * physically allocated on disk (not whether the inode is considered allocated * or free by the fs). * * A bit value of 1 means the inode is allocated, a value of 0 means it is free. */ uint64_t xfs_inobt_irec_to_allocmask( struct xfs_inobt_rec_incore *rec) { uint64_t bitmap = 0; uint64_t inodespbit; int nextbit; uint allocbitmap; /* * The holemask has 16-bits for a 64 inode record. Therefore each * holemask bit represents multiple inodes. Create a mask of bits to set * in the allocmask for each holemask bit. */ inodespbit = (1 << XFS_INODES_PER_HOLEMASK_BIT) - 1; /* * Allocated inodes are represented by 0 bits in holemask. Invert the 0 * bits to 1 and convert to a uint so we can use xfs_next_bit(). Mask * anything beyond the 16 holemask bits since this casts to a larger * type. */ allocbitmap = ~rec->ir_holemask & ((1 << XFS_INOBT_HOLEMASK_BITS) - 1); /* * allocbitmap is the inverted holemask so every set bit represents * allocated inodes. To expand from 16-bit holemask granularity to * 64-bit (e.g., bit-per-inode), set inodespbit bits in the target * bitmap for every holemask bit. */ nextbit = xfs_next_bit(&allocbitmap, 1, 0); while (nextbit != -1) { ASSERT(nextbit < (sizeof(rec->ir_holemask) * NBBY)); bitmap |= (inodespbit << (nextbit * XFS_INODES_PER_HOLEMASK_BIT)); nextbit = xfs_next_bit(&allocbitmap, 1, nextbit + 1); } return bitmap; } #if defined(DEBUG) || defined(XFS_WARN) /* * Verify that an in-core inode record has a valid inode count. */ int xfs_inobt_rec_check_count( struct xfs_mount *mp, struct xfs_inobt_rec_incore *rec) { int inocount = 0; int nextbit = 0; uint64_t allocbmap; int wordsz; wordsz = sizeof(allocbmap) / sizeof(unsigned int); allocbmap = xfs_inobt_irec_to_allocmask(rec); nextbit = xfs_next_bit((uint *) &allocbmap, wordsz, nextbit); while (nextbit != -1) { inocount++; nextbit = xfs_next_bit((uint *) &allocbmap, wordsz, nextbit + 1); } if (inocount != rec->ir_count) return -EFSCORRUPTED; return 0; } #endif /* DEBUG */ partclone-0.2.86/src/xfs/xfs_ialloc_btree.h000066400000000000000000000044701262102574200206500ustar00rootroot00000000000000/* * Copyright (c) 2000,2005 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __XFS_IALLOC_BTREE_H__ #define __XFS_IALLOC_BTREE_H__ /* * Inode map on-disk structures */ struct xfs_buf; struct xfs_btree_cur; struct xfs_mount; /* * Btree block header size depends on a superblock flag. */ #define XFS_INOBT_BLOCK_LEN(mp) \ (xfs_sb_version_hascrc(&((mp)->m_sb)) ? \ XFS_BTREE_SBLOCK_CRC_LEN : XFS_BTREE_SBLOCK_LEN) /* * Record, key, and pointer address macros for btree blocks. * * (note that some of these may appear unused, but they are used in userspace) */ #define XFS_INOBT_REC_ADDR(mp, block, index) \ ((xfs_inobt_rec_t *) \ ((char *)(block) + \ XFS_INOBT_BLOCK_LEN(mp) + \ (((index) - 1) * sizeof(xfs_inobt_rec_t)))) #define XFS_INOBT_KEY_ADDR(mp, block, index) \ ((xfs_inobt_key_t *) \ ((char *)(block) + \ XFS_INOBT_BLOCK_LEN(mp) + \ ((index) - 1) * sizeof(xfs_inobt_key_t))) #define XFS_INOBT_PTR_ADDR(mp, block, index, maxrecs) \ ((xfs_inobt_ptr_t *) \ ((char *)(block) + \ XFS_INOBT_BLOCK_LEN(mp) + \ (maxrecs) * sizeof(xfs_inobt_key_t) + \ ((index) - 1) * sizeof(xfs_inobt_ptr_t))) extern struct xfs_btree_cur *xfs_inobt_init_cursor(struct xfs_mount *, struct xfs_trans *, struct xfs_buf *, xfs_agnumber_t, xfs_btnum_t); extern int xfs_inobt_maxrecs(struct xfs_mount *, int, int); /* ir_holemask to inode allocation bitmap conversion */ uint64_t xfs_inobt_irec_to_allocmask(struct xfs_inobt_rec_incore *); #if defined(DEBUG) || defined(XFS_WARN) int xfs_inobt_rec_check_count(struct xfs_mount *, struct xfs_inobt_rec_incore *); #else #define xfs_inobt_rec_check_count(mp, rec) 0 #endif /* DEBUG */ #endif /* __XFS_IALLOC_BTREE_H__ */ partclone-0.2.86/src/xfs/xfs_inode.h000066400000000000000000000065131262102574200173220ustar00rootroot00000000000000/* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __XFS_INODE_H__ #define __XFS_INODE_H__ /* These match kernel side includes */ #include "xfs_inode_buf.h" #include "xfs_inode_fork.h" struct xfs_trans; struct xfs_mount; struct xfs_inode_log_item; struct xfs_dir_ops; /* * Inode interface */ typedef struct xfs_inode { struct cache_node i_node; struct xfs_mount *i_mount; /* fs mount struct ptr */ xfs_ino_t i_ino; /* inode number (agno/agino) */ struct xfs_imap i_imap; /* location for xfs_imap() */ struct xfs_buftarg i_dev; /* dev for this inode */ struct xfs_ifork *i_afp; /* attribute fork pointer */ struct xfs_ifork i_df; /* data fork */ struct xfs_trans *i_transp; /* ptr to owning transaction */ struct xfs_inode_log_item *i_itemp; /* logging information */ unsigned int i_delayed_blks; /* count of delay alloc blks */ struct xfs_icdinode i_d; /* most of ondisk inode */ xfs_fsize_t i_size; /* in-memory size */ const struct xfs_dir_ops *d_ops; /* directory ops vector */ } xfs_inode_t; /* * For regular files we only update the on-disk filesize when actually * writing data back to disk. Until then only the copy in the VFS inode * is uptodate. */ static inline xfs_fsize_t XFS_ISIZE(struct xfs_inode *ip) { if (S_ISREG(ip->i_d.di_mode)) return ip->i_size; return ip->i_d.di_size; } #define XFS_IS_REALTIME_INODE(ip) ((ip)->i_d.di_flags & XFS_DIFLAG_REALTIME) /* * Project quota id helpers (previously projid was 16bit only and using two * 16bit values to hold new 32bit projid was chosen to retain compatibility with * "old" filesystems). * * Copied here from xfs_inode.h because it has to be defined after the struct * xfs_inode... */ static inline prid_t xfs_get_projid(struct xfs_icdinode *id) { return (prid_t)id->di_projid_hi << 16 | id->di_projid_lo; } static inline void xfs_set_projid(struct xfs_icdinode *id, prid_t projid) { id->di_projid_hi = (__uint16_t) (projid >> 16); id->di_projid_lo = (__uint16_t) (projid & 0xffff); } typedef struct cred { uid_t cr_uid; gid_t cr_gid; } cred_t; extern int libxfs_inode_alloc (struct xfs_trans **, struct xfs_inode *, mode_t, nlink_t, xfs_dev_t, struct cred *, struct fsxattr *, struct xfs_inode **); extern void libxfs_trans_inode_alloc_buf (struct xfs_trans *, struct xfs_buf *); extern void libxfs_trans_ichgtime(struct xfs_trans *, struct xfs_inode *, int); extern int libxfs_iflush_int (struct xfs_inode *, struct xfs_buf *); /* Inode Cache Interfaces */ extern int libxfs_iget(struct xfs_mount *, struct xfs_trans *, xfs_ino_t, uint, struct xfs_inode **, xfs_daddr_t); extern void libxfs_iput(struct xfs_inode *); #define IRELE(ip) libxfs_iput(ip) #endif /* __XFS_INODE_H__ */ partclone-0.2.86/src/xfs/xfs_inode_buf.c000066400000000000000000000342341262102574200201520ustar00rootroot00000000000000/* * Copyright (c) 2000-2006 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_mount.h" #include "xfs_inode.h" #include "xfs_cksum.h" #include "xfs_trans.h" #include "xfs_ialloc.h" /* * Check that none of the inode's in the buffer have a next * unlinked field of 0. */ #if defined(DEBUG) void xfs_inobp_check( xfs_mount_t *mp, xfs_buf_t *bp) { int i; int j; xfs_dinode_t *dip; j = mp->m_inode_cluster_size >> mp->m_sb.sb_inodelog; for (i = 0; i < j; i++) { dip = xfs_buf_offset(bp, i * mp->m_sb.sb_inodesize); if (!dip->di_next_unlinked) { xfs_alert(mp, "Detected bogus zero next_unlinked field in inode %d buffer 0x%llx.", i, (long long)bp->b_bn); } } } #endif bool xfs_dinode_good_version( struct xfs_mount *mp, __u8 version) { if (xfs_sb_version_hascrc(&mp->m_sb)) return version == 3; return version == 1 || version == 2; } /* * If we are doing readahead on an inode buffer, we might be in log recovery * reading an inode allocation buffer that hasn't yet been replayed, and hence * has not had the inode cores stamped into it. Hence for readahead, the buffer * may be potentially invalid. * * If the readahead buffer is invalid, we don't want to mark it with an error, * but we do want to clear the DONE status of the buffer so that a followup read * will re-read it from disk. This will ensure that we don't get an unnecessary * warnings during log recovery and we don't get unnecssary panics on debug * kernels. */ static void xfs_inode_buf_verify( struct xfs_buf *bp, bool readahead) { struct xfs_mount *mp = bp->b_target->bt_mount; int i; int ni; /* * Validate the magic number and version of every inode in the buffer */ ni = XFS_BB_TO_FSB(mp, bp->b_length) * mp->m_sb.sb_inopblock; for (i = 0; i < ni; i++) { int di_ok; xfs_dinode_t *dip; dip = xfs_buf_offset(bp, (i << mp->m_sb.sb_inodelog)); di_ok = dip->di_magic == cpu_to_be16(XFS_DINODE_MAGIC) && xfs_dinode_good_version(mp, dip->di_version); if (unlikely(XFS_TEST_ERROR(!di_ok, mp, XFS_ERRTAG_ITOBP_INOTOBP, XFS_RANDOM_ITOBP_INOTOBP))) { if (readahead) { bp->b_flags &= ~XBF_DONE; return; } xfs_buf_ioerror(bp, -EFSCORRUPTED); xfs_verifier_error(bp); #ifdef DEBUG xfs_alert(mp, "bad inode magic/vsn daddr %lld #%d (magic=%x)", (unsigned long long)bp->b_bn, i, be16_to_cpu(dip->di_magic)); #endif } } xfs_inobp_check(mp, bp); } static void xfs_inode_buf_read_verify( struct xfs_buf *bp) { xfs_inode_buf_verify(bp, false); } static void xfs_inode_buf_readahead_verify( struct xfs_buf *bp) { xfs_inode_buf_verify(bp, true); } static void xfs_inode_buf_write_verify( struct xfs_buf *bp) { xfs_inode_buf_verify(bp, false); } const struct xfs_buf_ops xfs_inode_buf_ops = { .verify_read = xfs_inode_buf_read_verify, .verify_write = xfs_inode_buf_write_verify, }; const struct xfs_buf_ops xfs_inode_buf_ra_ops = { .verify_read = xfs_inode_buf_readahead_verify, .verify_write = xfs_inode_buf_write_verify, }; /* * This routine is called to map an inode to the buffer containing the on-disk * version of the inode. It returns a pointer to the buffer containing the * on-disk inode in the bpp parameter, and in the dipp parameter it returns a * pointer to the on-disk inode within that buffer. * * If a non-zero error is returned, then the contents of bpp and dipp are * undefined. */ int xfs_imap_to_bp( struct xfs_mount *mp, struct xfs_trans *tp, struct xfs_imap *imap, struct xfs_dinode **dipp, struct xfs_buf **bpp, uint buf_flags, uint iget_flags) { struct xfs_buf *bp; int error; buf_flags |= XBF_UNMAPPED; error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, imap->im_blkno, (int)imap->im_len, buf_flags, &bp, &xfs_inode_buf_ops); if (error) { if (error == -EAGAIN) { ASSERT(buf_flags & XBF_TRYLOCK); return error; } if (error == -EFSCORRUPTED && (iget_flags & XFS_IGET_UNTRUSTED)) return -EINVAL; xfs_warn(mp, "%s: xfs_trans_read_buf() returned error %d.", __func__, error); return error; } *bpp = bp; *dipp = xfs_buf_offset(bp, imap->im_boffset); return 0; } void xfs_dinode_from_disk( xfs_icdinode_t *to, xfs_dinode_t *from) { to->di_magic = be16_to_cpu(from->di_magic); to->di_mode = be16_to_cpu(from->di_mode); to->di_version = from ->di_version; to->di_format = from->di_format; to->di_onlink = be16_to_cpu(from->di_onlink); to->di_uid = be32_to_cpu(from->di_uid); to->di_gid = be32_to_cpu(from->di_gid); to->di_nlink = be32_to_cpu(from->di_nlink); to->di_projid_lo = be16_to_cpu(from->di_projid_lo); to->di_projid_hi = be16_to_cpu(from->di_projid_hi); memcpy(to->di_pad, from->di_pad, sizeof(to->di_pad)); to->di_flushiter = be16_to_cpu(from->di_flushiter); to->di_atime.t_sec = be32_to_cpu(from->di_atime.t_sec); to->di_atime.t_nsec = be32_to_cpu(from->di_atime.t_nsec); to->di_mtime.t_sec = be32_to_cpu(from->di_mtime.t_sec); to->di_mtime.t_nsec = be32_to_cpu(from->di_mtime.t_nsec); to->di_ctime.t_sec = be32_to_cpu(from->di_ctime.t_sec); to->di_ctime.t_nsec = be32_to_cpu(from->di_ctime.t_nsec); to->di_size = be64_to_cpu(from->di_size); to->di_nblocks = be64_to_cpu(from->di_nblocks); to->di_extsize = be32_to_cpu(from->di_extsize); to->di_nextents = be32_to_cpu(from->di_nextents); to->di_anextents = be16_to_cpu(from->di_anextents); to->di_forkoff = from->di_forkoff; to->di_aformat = from->di_aformat; to->di_dmevmask = be32_to_cpu(from->di_dmevmask); to->di_dmstate = be16_to_cpu(from->di_dmstate); to->di_flags = be16_to_cpu(from->di_flags); to->di_gen = be32_to_cpu(from->di_gen); if (to->di_version == 3) { to->di_changecount = be64_to_cpu(from->di_changecount); to->di_crtime.t_sec = be32_to_cpu(from->di_crtime.t_sec); to->di_crtime.t_nsec = be32_to_cpu(from->di_crtime.t_nsec); to->di_flags2 = be64_to_cpu(from->di_flags2); to->di_ino = be64_to_cpu(from->di_ino); to->di_lsn = be64_to_cpu(from->di_lsn); memcpy(to->di_pad2, from->di_pad2, sizeof(to->di_pad2)); uuid_copy(&to->di_uuid, &from->di_uuid); } } void xfs_dinode_to_disk( xfs_dinode_t *to, xfs_icdinode_t *from) { to->di_magic = cpu_to_be16(from->di_magic); to->di_mode = cpu_to_be16(from->di_mode); to->di_version = from ->di_version; to->di_format = from->di_format; to->di_onlink = cpu_to_be16(from->di_onlink); to->di_uid = cpu_to_be32(from->di_uid); to->di_gid = cpu_to_be32(from->di_gid); to->di_nlink = cpu_to_be32(from->di_nlink); to->di_projid_lo = cpu_to_be16(from->di_projid_lo); to->di_projid_hi = cpu_to_be16(from->di_projid_hi); memcpy(to->di_pad, from->di_pad, sizeof(to->di_pad)); to->di_atime.t_sec = cpu_to_be32(from->di_atime.t_sec); to->di_atime.t_nsec = cpu_to_be32(from->di_atime.t_nsec); to->di_mtime.t_sec = cpu_to_be32(from->di_mtime.t_sec); to->di_mtime.t_nsec = cpu_to_be32(from->di_mtime.t_nsec); to->di_ctime.t_sec = cpu_to_be32(from->di_ctime.t_sec); to->di_ctime.t_nsec = cpu_to_be32(from->di_ctime.t_nsec); to->di_size = cpu_to_be64(from->di_size); to->di_nblocks = cpu_to_be64(from->di_nblocks); to->di_extsize = cpu_to_be32(from->di_extsize); to->di_nextents = cpu_to_be32(from->di_nextents); to->di_anextents = cpu_to_be16(from->di_anextents); to->di_forkoff = from->di_forkoff; to->di_aformat = from->di_aformat; to->di_dmevmask = cpu_to_be32(from->di_dmevmask); to->di_dmstate = cpu_to_be16(from->di_dmstate); to->di_flags = cpu_to_be16(from->di_flags); to->di_gen = cpu_to_be32(from->di_gen); if (from->di_version == 3) { to->di_changecount = cpu_to_be64(from->di_changecount); to->di_crtime.t_sec = cpu_to_be32(from->di_crtime.t_sec); to->di_crtime.t_nsec = cpu_to_be32(from->di_crtime.t_nsec); to->di_flags2 = cpu_to_be64(from->di_flags2); to->di_ino = cpu_to_be64(from->di_ino); to->di_lsn = cpu_to_be64(from->di_lsn); memcpy(to->di_pad2, from->di_pad2, sizeof(to->di_pad2)); uuid_copy(&to->di_uuid, &from->di_uuid); to->di_flushiter = 0; } else { to->di_flushiter = cpu_to_be16(from->di_flushiter); } } bool xfs_dinode_verify( struct xfs_mount *mp, xfs_ino_t ino, struct xfs_dinode *dip) { if (dip->di_magic != cpu_to_be16(XFS_DINODE_MAGIC)) return false; /* only version 3 or greater inodes are extensively verified here */ if (dip->di_version < 3) return true; if (!xfs_sb_version_hascrc(&mp->m_sb)) return false; if (!xfs_verify_cksum((char *)dip, mp->m_sb.sb_inodesize, XFS_DINODE_CRC_OFF)) return false; if (be64_to_cpu(dip->di_ino) != ino) return false; if (!uuid_equal(&dip->di_uuid, &mp->m_sb.sb_meta_uuid)) return false; return true; } void xfs_dinode_calc_crc( struct xfs_mount *mp, struct xfs_dinode *dip) { __uint32_t crc; if (dip->di_version < 3) return; ASSERT(xfs_sb_version_hascrc(&mp->m_sb)); crc = xfs_start_cksum((char *)dip, mp->m_sb.sb_inodesize, XFS_DINODE_CRC_OFF); dip->di_crc = xfs_end_cksum(crc); } /* * Read the disk inode attributes into the in-core inode structure. * * For version 5 superblocks, if we are initialising a new inode and we are not * utilising the XFS_MOUNT_IKEEP inode cluster mode, we can simple build the new * inode core with a random generation number. If we are keeping inodes around, * we need to read the inode cluster to get the existing generation number off * disk. Further, if we are using version 4 superblocks (i.e. v1/v2 inode * format) then log recovery is dependent on the di_flushiter field being * initialised from the current on-disk value and hence we must also read the * inode off disk. */ int xfs_iread( xfs_mount_t *mp, xfs_trans_t *tp, xfs_inode_t *ip, uint iget_flags) { xfs_buf_t *bp; xfs_dinode_t *dip; int error; /* * Fill in the location information in the in-core inode. */ error = xfs_imap(mp, tp, ip->i_ino, &ip->i_imap, iget_flags); if (error) return error; /* shortcut IO on inode allocation if possible */ if ((iget_flags & XFS_IGET_CREATE) && xfs_sb_version_hascrc(&mp->m_sb) && !(mp->m_flags & XFS_MOUNT_IKEEP)) { /* initialise the on-disk inode core */ memset(&ip->i_d, 0, sizeof(ip->i_d)); ip->i_d.di_magic = XFS_DINODE_MAGIC; ip->i_d.di_gen = prandom_u32(); if (xfs_sb_version_hascrc(&mp->m_sb)) { ip->i_d.di_version = 3; ip->i_d.di_ino = ip->i_ino; uuid_copy(&ip->i_d.di_uuid, &mp->m_sb.sb_meta_uuid); } else ip->i_d.di_version = 2; return 0; } /* * Get pointers to the on-disk inode and the buffer containing it. */ error = xfs_imap_to_bp(mp, tp, &ip->i_imap, &dip, &bp, 0, iget_flags); if (error) return error; /* even unallocated inodes are verified */ if (!xfs_dinode_verify(mp, ip->i_ino, dip)) { xfs_alert(mp, "%s: validation failed for inode %lld failed", __func__, ip->i_ino); XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, dip); error = -EFSCORRUPTED; goto out_brelse; } /* * If the on-disk inode is already linked to a directory * entry, copy all of the inode into the in-core inode. * xfs_iformat_fork() handles copying in the inode format * specific information. * Otherwise, just get the truly permanent information. */ if (dip->di_mode) { xfs_dinode_from_disk(&ip->i_d, dip); error = xfs_iformat_fork(ip, dip); if (error) { #ifdef DEBUG xfs_alert(mp, "%s: xfs_iformat() returned error %d", __func__, error); #endif /* DEBUG */ goto out_brelse; } } else { /* * Partial initialisation of the in-core inode. Just the bits * that xfs_ialloc won't overwrite or relies on being correct. */ ip->i_d.di_magic = be16_to_cpu(dip->di_magic); ip->i_d.di_version = dip->di_version; ip->i_d.di_gen = be32_to_cpu(dip->di_gen); ip->i_d.di_flushiter = be16_to_cpu(dip->di_flushiter); if (dip->di_version == 3) { ip->i_d.di_ino = be64_to_cpu(dip->di_ino); uuid_copy(&ip->i_d.di_uuid, &dip->di_uuid); } /* * Make sure to pull in the mode here as well in * case the inode is released without being used. * This ensures that xfs_inactive() will see that * the inode is already free and not try to mess * with the uninitialized part of it. */ ip->i_d.di_mode = 0; } /* * Automatically convert version 1 inode formats in memory to version 2 * inode format. If the inode is modified, it will get logged and * rewritten as a version 2 inode. We can do this because we set the * superblock feature bit for v2 inodes unconditionally during mount * and it means the reast of the code can assume the inode version is 2 * or higher. */ if (ip->i_d.di_version == 1) { ip->i_d.di_version = 2; memset(&(ip->i_d.di_pad[0]), 0, sizeof(ip->i_d.di_pad)); ip->i_d.di_nlink = ip->i_d.di_onlink; ip->i_d.di_onlink = 0; xfs_set_projid(&ip->i_d, 0); } ip->i_delayed_blks = 0; /* * Mark the buffer containing the inode as something to keep * around for a while. This helps to keep recently accessed * meta-data in-core longer. */ xfs_buf_set_ref(bp, XFS_INO_REF); /* * Use xfs_trans_brelse() to release the buffer containing the on-disk * inode, because it was acquired with xfs_trans_read_buf() in * xfs_imap_to_bp() above. If tp is NULL, this is just a normal * brelse(). If we're within a transaction, then xfs_trans_brelse() * will only release the buffer if it is not dirty within the * transaction. It will be OK to release the buffer in this case, * because inodes on disk are never destroyed and we will be locking the * new in-core inode before putting it in the cache where other * processes can find it. Thus we don't have to worry about the inode * being changed just because we released the buffer. */ out_brelse: xfs_trans_brelse(tp, bp); return error; } partclone-0.2.86/src/xfs/xfs_inode_buf.h000066400000000000000000000036571262102574200201640ustar00rootroot00000000000000/* * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __XFS_INODE_BUF_H__ #define __XFS_INODE_BUF_H__ struct xfs_inode; struct xfs_dinode; struct xfs_icdinode; /* * Inode location information. Stored in the inode and passed to * xfs_imap_to_bp() to get a buffer and dinode for a given inode. */ struct xfs_imap { xfs_daddr_t im_blkno; /* starting BB of inode chunk */ unsigned short im_len; /* length in BBs of inode chunk */ unsigned short im_boffset; /* inode offset in block in bytes */ }; int xfs_imap_to_bp(struct xfs_mount *, struct xfs_trans *, struct xfs_imap *, struct xfs_dinode **, struct xfs_buf **, uint, uint); int xfs_iread(struct xfs_mount *, struct xfs_trans *, struct xfs_inode *, uint); void xfs_dinode_calc_crc(struct xfs_mount *, struct xfs_dinode *); void xfs_dinode_to_disk(struct xfs_dinode *to, struct xfs_icdinode *from); void xfs_dinode_from_disk(struct xfs_icdinode *to, struct xfs_dinode *from); bool xfs_dinode_verify(struct xfs_mount *mp, xfs_ino_t ino, struct xfs_dinode *dip); bool xfs_dinode_good_version(struct xfs_mount *mp, __u8 version); #if defined(DEBUG) void xfs_inobp_check(struct xfs_mount *, struct xfs_buf *); #else #define xfs_inobp_check(mp, bp) #endif /* DEBUG */ #endif /* __XFS_INODE_BUF_H__ */ partclone-0.2.86/src/xfs/xfs_inode_fork.c000066400000000000000000001560241262102574200203410ustar00rootroot00000000000000/* * Copyright (c) 2000-2006 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_mount.h" #include "xfs_inode.h" #include "xfs_trans.h" #include "xfs_bmap_btree.h" #include "xfs_bmap.h" #include "xfs_trace.h" #include "xfs_attr_sf.h" kmem_zone_t *xfs_ifork_zone; STATIC int xfs_iformat_local(xfs_inode_t *, xfs_dinode_t *, int, int); STATIC int xfs_iformat_extents(xfs_inode_t *, xfs_dinode_t *, int); STATIC int xfs_iformat_btree(xfs_inode_t *, xfs_dinode_t *, int); #ifdef DEBUG /* * Make sure that the extents in the given memory buffer * are valid. */ void xfs_validate_extents( xfs_ifork_t *ifp, int nrecs, xfs_exntfmt_t fmt) { xfs_bmbt_irec_t irec; xfs_bmbt_rec_host_t rec; int i; for (i = 0; i < nrecs; i++) { xfs_bmbt_rec_host_t *ep = xfs_iext_get_ext(ifp, i); rec.l0 = get_unaligned(&ep->l0); rec.l1 = get_unaligned(&ep->l1); xfs_bmbt_get_all(&rec, &irec); if (fmt == XFS_EXTFMT_NOSTATE) ASSERT(irec.br_state == XFS_EXT_NORM); } } #else /* DEBUG */ #define xfs_validate_extents(ifp, nrecs, fmt) #endif /* DEBUG */ /* * Move inode type and inode format specific information from the * on-disk inode to the in-core inode. For fifos, devs, and sockets * this means set if_rdev to the proper value. For files, directories, * and symlinks this means to bring in the in-line data or extent * pointers. For a file in B-tree format, only the root is immediately * brought in-core. The rest will be in-lined in if_extents when it * is first referenced (see xfs_iread_extents()). */ int xfs_iformat_fork( xfs_inode_t *ip, xfs_dinode_t *dip) { xfs_attr_shortform_t *atp; int size; int error = 0; xfs_fsize_t di_size; if (unlikely(be32_to_cpu(dip->di_nextents) + be16_to_cpu(dip->di_anextents) > be64_to_cpu(dip->di_nblocks))) { xfs_warn(ip->i_mount, "corrupt dinode %Lu, extent total = %d, nblocks = %Lu.", (unsigned long long)ip->i_ino, (int)(be32_to_cpu(dip->di_nextents) + be16_to_cpu(dip->di_anextents)), (unsigned long long) be64_to_cpu(dip->di_nblocks)); XFS_CORRUPTION_ERROR("xfs_iformat(1)", XFS_ERRLEVEL_LOW, ip->i_mount, dip); return -EFSCORRUPTED; } if (unlikely(dip->di_forkoff > ip->i_mount->m_sb.sb_inodesize)) { xfs_warn(ip->i_mount, "corrupt dinode %Lu, forkoff = 0x%x.", (unsigned long long)ip->i_ino, dip->di_forkoff); XFS_CORRUPTION_ERROR("xfs_iformat(2)", XFS_ERRLEVEL_LOW, ip->i_mount, dip); return -EFSCORRUPTED; } if (unlikely((ip->i_d.di_flags & XFS_DIFLAG_REALTIME) && !ip->i_mount->m_rtdev_targp)) { xfs_warn(ip->i_mount, "corrupt dinode %Lu, has realtime flag set.", ip->i_ino); XFS_CORRUPTION_ERROR("xfs_iformat(realtime)", XFS_ERRLEVEL_LOW, ip->i_mount, dip); return -EFSCORRUPTED; } switch (ip->i_d.di_mode & S_IFMT) { case S_IFIFO: case S_IFCHR: case S_IFBLK: case S_IFSOCK: if (unlikely(dip->di_format != XFS_DINODE_FMT_DEV)) { XFS_CORRUPTION_ERROR("xfs_iformat(3)", XFS_ERRLEVEL_LOW, ip->i_mount, dip); return -EFSCORRUPTED; } ip->i_d.di_size = 0; ip->i_df.if_u2.if_rdev = xfs_dinode_get_rdev(dip); break; case S_IFREG: case S_IFLNK: case S_IFDIR: switch (dip->di_format) { case XFS_DINODE_FMT_LOCAL: /* * no local regular files yet */ if (unlikely(S_ISREG(be16_to_cpu(dip->di_mode)))) { xfs_warn(ip->i_mount, "corrupt inode %Lu (local format for regular file).", (unsigned long long) ip->i_ino); XFS_CORRUPTION_ERROR("xfs_iformat(4)", XFS_ERRLEVEL_LOW, ip->i_mount, dip); return -EFSCORRUPTED; } di_size = be64_to_cpu(dip->di_size); if (unlikely(di_size < 0 || di_size > XFS_DFORK_DSIZE(dip, ip->i_mount))) { xfs_warn(ip->i_mount, "corrupt inode %Lu (bad size %Ld for local inode).", (unsigned long long) ip->i_ino, (long long) di_size); XFS_CORRUPTION_ERROR("xfs_iformat(5)", XFS_ERRLEVEL_LOW, ip->i_mount, dip); return -EFSCORRUPTED; } size = (int)di_size; error = xfs_iformat_local(ip, dip, XFS_DATA_FORK, size); break; case XFS_DINODE_FMT_EXTENTS: error = xfs_iformat_extents(ip, dip, XFS_DATA_FORK); break; case XFS_DINODE_FMT_BTREE: error = xfs_iformat_btree(ip, dip, XFS_DATA_FORK); break; default: XFS_ERROR_REPORT("xfs_iformat(6)", XFS_ERRLEVEL_LOW, ip->i_mount); return -EFSCORRUPTED; } break; default: XFS_ERROR_REPORT("xfs_iformat(7)", XFS_ERRLEVEL_LOW, ip->i_mount); return -EFSCORRUPTED; } if (error) { return error; } if (!XFS_DFORK_Q(dip)) return 0; ASSERT(ip->i_afp == NULL); ip->i_afp = kmem_zone_zalloc(xfs_ifork_zone, KM_SLEEP | KM_NOFS); switch (dip->di_aformat) { case XFS_DINODE_FMT_LOCAL: atp = (xfs_attr_shortform_t *)XFS_DFORK_APTR(dip); size = be16_to_cpu(atp->hdr.totsize); if (unlikely(size < sizeof(struct xfs_attr_sf_hdr))) { xfs_warn(ip->i_mount, "corrupt inode %Lu (bad attr fork size %Ld).", (unsigned long long) ip->i_ino, (long long) size); XFS_CORRUPTION_ERROR("xfs_iformat(8)", XFS_ERRLEVEL_LOW, ip->i_mount, dip); return -EFSCORRUPTED; } error = xfs_iformat_local(ip, dip, XFS_ATTR_FORK, size); break; case XFS_DINODE_FMT_EXTENTS: error = xfs_iformat_extents(ip, dip, XFS_ATTR_FORK); break; case XFS_DINODE_FMT_BTREE: error = xfs_iformat_btree(ip, dip, XFS_ATTR_FORK); break; default: error = -EFSCORRUPTED; break; } if (error) { kmem_zone_free(xfs_ifork_zone, ip->i_afp); ip->i_afp = NULL; xfs_idestroy_fork(ip, XFS_DATA_FORK); } return error; } /* * The file is in-lined in the on-disk inode. * If it fits into if_inline_data, then copy * it there, otherwise allocate a buffer for it * and copy the data there. Either way, set * if_data to point at the data. * If we allocate a buffer for the data, make * sure that its size is a multiple of 4 and * record the real size in i_real_bytes. */ STATIC int xfs_iformat_local( xfs_inode_t *ip, xfs_dinode_t *dip, int whichfork, int size) { xfs_ifork_t *ifp; int real_size; /* * If the size is unreasonable, then something * is wrong and we just bail out rather than crash in * kmem_alloc() or memcpy() below. */ if (unlikely(size > XFS_DFORK_SIZE(dip, ip->i_mount, whichfork))) { xfs_warn(ip->i_mount, "corrupt inode %Lu (bad size %d for local fork, size = %d).", (unsigned long long) ip->i_ino, size, XFS_DFORK_SIZE(dip, ip->i_mount, whichfork)); XFS_CORRUPTION_ERROR("xfs_iformat_local", XFS_ERRLEVEL_LOW, ip->i_mount, dip); return -EFSCORRUPTED; } ifp = XFS_IFORK_PTR(ip, whichfork); real_size = 0; if (size == 0) ifp->if_u1.if_data = NULL; else if (size <= sizeof(ifp->if_u2.if_inline_data)) ifp->if_u1.if_data = ifp->if_u2.if_inline_data; else { real_size = roundup(size, 4); ifp->if_u1.if_data = kmem_alloc(real_size, KM_SLEEP | KM_NOFS); } ifp->if_bytes = size; ifp->if_real_bytes = real_size; if (size) memcpy(ifp->if_u1.if_data, XFS_DFORK_PTR(dip, whichfork), size); ifp->if_flags &= ~XFS_IFEXTENTS; ifp->if_flags |= XFS_IFINLINE; return 0; } /* * The file consists of a set of extents all * of which fit into the on-disk inode. * If there are few enough extents to fit into * the if_inline_ext, then copy them there. * Otherwise allocate a buffer for them and copy * them into it. Either way, set if_extents * to point at the extents. */ STATIC int xfs_iformat_extents( xfs_inode_t *ip, xfs_dinode_t *dip, int whichfork) { xfs_bmbt_rec_t *dp; xfs_ifork_t *ifp; int nex; int size; int i; ifp = XFS_IFORK_PTR(ip, whichfork); nex = XFS_DFORK_NEXTENTS(dip, whichfork); size = nex * (uint)sizeof(xfs_bmbt_rec_t); /* * If the number of extents is unreasonable, then something * is wrong and we just bail out rather than crash in * kmem_alloc() or memcpy() below. */ if (unlikely(size < 0 || size > XFS_DFORK_SIZE(dip, ip->i_mount, whichfork))) { xfs_warn(ip->i_mount, "corrupt inode %Lu ((a)extents = %d).", (unsigned long long) ip->i_ino, nex); XFS_CORRUPTION_ERROR("xfs_iformat_extents(1)", XFS_ERRLEVEL_LOW, ip->i_mount, dip); return -EFSCORRUPTED; } ifp->if_real_bytes = 0; if (nex == 0) ifp->if_u1.if_extents = NULL; else if (nex <= XFS_INLINE_EXTS) ifp->if_u1.if_extents = ifp->if_u2.if_inline_ext; else xfs_iext_add(ifp, 0, nex); ifp->if_bytes = size; if (size) { dp = (xfs_bmbt_rec_t *) XFS_DFORK_PTR(dip, whichfork); xfs_validate_extents(ifp, nex, XFS_EXTFMT_INODE(ip)); for (i = 0; i < nex; i++, dp++) { xfs_bmbt_rec_host_t *ep = xfs_iext_get_ext(ifp, i); ep->l0 = get_unaligned_be64(&dp->l0); ep->l1 = get_unaligned_be64(&dp->l1); } XFS_BMAP_TRACE_EXLIST(ip, nex, whichfork); if (whichfork != XFS_DATA_FORK || XFS_EXTFMT_INODE(ip) == XFS_EXTFMT_NOSTATE) if (unlikely(xfs_check_nostate_extents( ifp, 0, nex))) { XFS_ERROR_REPORT("xfs_iformat_extents(2)", XFS_ERRLEVEL_LOW, ip->i_mount); return -EFSCORRUPTED; } } ifp->if_flags |= XFS_IFEXTENTS; return 0; } /* * The file has too many extents to fit into * the inode, so they are in B-tree format. * Allocate a buffer for the root of the B-tree * and copy the root into it. The i_extents * field will remain NULL until all of the * extents are read in (when they are needed). */ STATIC int xfs_iformat_btree( xfs_inode_t *ip, xfs_dinode_t *dip, int whichfork) { struct xfs_mount *mp = ip->i_mount; xfs_bmdr_block_t *dfp; xfs_ifork_t *ifp; /* REFERENCED */ int nrecs; int size; ifp = XFS_IFORK_PTR(ip, whichfork); dfp = (xfs_bmdr_block_t *)XFS_DFORK_PTR(dip, whichfork); size = XFS_BMAP_BROOT_SPACE(mp, dfp); nrecs = be16_to_cpu(dfp->bb_numrecs); /* * blow out if -- fork has less extents than can fit in * fork (fork shouldn't be a btree format), root btree * block has more records than can fit into the fork, * or the number of extents is greater than the number of * blocks. */ if (unlikely(XFS_IFORK_NEXTENTS(ip, whichfork) <= XFS_IFORK_MAXEXT(ip, whichfork) || XFS_BMDR_SPACE_CALC(nrecs) > XFS_DFORK_SIZE(dip, mp, whichfork) || XFS_IFORK_NEXTENTS(ip, whichfork) > ip->i_d.di_nblocks)) { xfs_warn(mp, "corrupt inode %Lu (btree).", (unsigned long long) ip->i_ino); XFS_CORRUPTION_ERROR("xfs_iformat_btree", XFS_ERRLEVEL_LOW, mp, dip); return -EFSCORRUPTED; } ifp->if_broot_bytes = size; ifp->if_broot = kmem_alloc(size, KM_SLEEP | KM_NOFS); ASSERT(ifp->if_broot != NULL); /* * Copy and convert from the on-disk structure * to the in-memory structure. */ xfs_bmdr_to_bmbt(ip, dfp, XFS_DFORK_SIZE(dip, ip->i_mount, whichfork), ifp->if_broot, size); ifp->if_flags &= ~XFS_IFEXTENTS; ifp->if_flags |= XFS_IFBROOT; return 0; } /* * Read in extents from a btree-format inode. * Allocate and fill in if_extents. Real work is done in xfs_bmap.c. */ int xfs_iread_extents( xfs_trans_t *tp, xfs_inode_t *ip, int whichfork) { int error; xfs_ifork_t *ifp; xfs_extnum_t nextents; ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); if (unlikely(XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE)) { XFS_ERROR_REPORT("xfs_iread_extents", XFS_ERRLEVEL_LOW, ip->i_mount); return -EFSCORRUPTED; } nextents = XFS_IFORK_NEXTENTS(ip, whichfork); ifp = XFS_IFORK_PTR(ip, whichfork); /* * We know that the size is valid (it's checked in iformat_btree) */ ifp->if_bytes = ifp->if_real_bytes = 0; ifp->if_flags |= XFS_IFEXTENTS; xfs_iext_add(ifp, 0, nextents); error = xfs_bmap_read_extents(tp, ip, whichfork); if (error) { xfs_iext_destroy(ifp); ifp->if_flags &= ~XFS_IFEXTENTS; return error; } xfs_validate_extents(ifp, nextents, XFS_EXTFMT_INODE(ip)); return 0; } /* * Reallocate the space for if_broot based on the number of records * being added or deleted as indicated in rec_diff. Move the records * and pointers in if_broot to fit the new size. When shrinking this * will eliminate holes between the records and pointers created by * the caller. When growing this will create holes to be filled in * by the caller. * * The caller must not request to add more records than would fit in * the on-disk inode root. If the if_broot is currently NULL, then * if we are adding records, one will be allocated. The caller must also * not request that the number of records go below zero, although * it can go to zero. * * ip -- the inode whose if_broot area is changing * ext_diff -- the change in the number of records, positive or negative, * requested for the if_broot array. */ void xfs_iroot_realloc( xfs_inode_t *ip, int rec_diff, int whichfork) { struct xfs_mount *mp = ip->i_mount; int cur_max; xfs_ifork_t *ifp; struct xfs_btree_block *new_broot; int new_max; size_t new_size; char *np; char *op; /* * Handle the degenerate case quietly. */ if (rec_diff == 0) { return; } ifp = XFS_IFORK_PTR(ip, whichfork); if (rec_diff > 0) { /* * If there wasn't any memory allocated before, just * allocate it now and get out. */ if (ifp->if_broot_bytes == 0) { new_size = XFS_BMAP_BROOT_SPACE_CALC(mp, rec_diff); ifp->if_broot = kmem_alloc(new_size, KM_SLEEP | KM_NOFS); ifp->if_broot_bytes = (int)new_size; return; } /* * If there is already an existing if_broot, then we need * to realloc() it and shift the pointers to their new * location. The records don't change location because * they are kept butted up against the btree block header. */ cur_max = xfs_bmbt_maxrecs(mp, ifp->if_broot_bytes, 0); new_max = cur_max + rec_diff; new_size = XFS_BMAP_BROOT_SPACE_CALC(mp, new_max); ifp->if_broot = kmem_realloc(ifp->if_broot, new_size, XFS_BMAP_BROOT_SPACE_CALC(mp, cur_max), KM_SLEEP | KM_NOFS); op = (char *)XFS_BMAP_BROOT_PTR_ADDR(mp, ifp->if_broot, 1, ifp->if_broot_bytes); np = (char *)XFS_BMAP_BROOT_PTR_ADDR(mp, ifp->if_broot, 1, (int)new_size); ifp->if_broot_bytes = (int)new_size; ASSERT(XFS_BMAP_BMDR_SPACE(ifp->if_broot) <= XFS_IFORK_SIZE(ip, whichfork)); memmove(np, op, cur_max * (uint)sizeof(xfs_fsblock_t)); return; } /* * rec_diff is less than 0. In this case, we are shrinking the * if_broot buffer. It must already exist. If we go to zero * records, just get rid of the root and clear the status bit. */ ASSERT((ifp->if_broot != NULL) && (ifp->if_broot_bytes > 0)); cur_max = xfs_bmbt_maxrecs(mp, ifp->if_broot_bytes, 0); new_max = cur_max + rec_diff; ASSERT(new_max >= 0); if (new_max > 0) new_size = XFS_BMAP_BROOT_SPACE_CALC(mp, new_max); else new_size = 0; if (new_size > 0) { new_broot = kmem_alloc(new_size, KM_SLEEP | KM_NOFS); /* * First copy over the btree block header. */ memcpy(new_broot, ifp->if_broot, XFS_BMBT_BLOCK_LEN(ip->i_mount)); } else { new_broot = NULL; ifp->if_flags &= ~XFS_IFBROOT; } /* * Only copy the records and pointers if there are any. */ if (new_max > 0) { /* * First copy the records. */ op = (char *)XFS_BMBT_REC_ADDR(mp, ifp->if_broot, 1); np = (char *)XFS_BMBT_REC_ADDR(mp, new_broot, 1); memcpy(np, op, new_max * (uint)sizeof(xfs_bmbt_rec_t)); /* * Then copy the pointers. */ op = (char *)XFS_BMAP_BROOT_PTR_ADDR(mp, ifp->if_broot, 1, ifp->if_broot_bytes); np = (char *)XFS_BMAP_BROOT_PTR_ADDR(mp, new_broot, 1, (int)new_size); memcpy(np, op, new_max * (uint)sizeof(xfs_fsblock_t)); } kmem_free(ifp->if_broot); ifp->if_broot = new_broot; ifp->if_broot_bytes = (int)new_size; if (ifp->if_broot) ASSERT(XFS_BMAP_BMDR_SPACE(ifp->if_broot) <= XFS_IFORK_SIZE(ip, whichfork)); return; } /* * This is called when the amount of space needed for if_data * is increased or decreased. The change in size is indicated by * the number of bytes that need to be added or deleted in the * byte_diff parameter. * * If the amount of space needed has decreased below the size of the * inline buffer, then switch to using the inline buffer. Otherwise, * use kmem_realloc() or kmem_alloc() to adjust the size of the buffer * to what is needed. * * ip -- the inode whose if_data area is changing * byte_diff -- the change in the number of bytes, positive or negative, * requested for the if_data array. */ void xfs_idata_realloc( xfs_inode_t *ip, int byte_diff, int whichfork) { xfs_ifork_t *ifp; int new_size; int real_size; if (byte_diff == 0) { return; } ifp = XFS_IFORK_PTR(ip, whichfork); new_size = (int)ifp->if_bytes + byte_diff; ASSERT(new_size >= 0); if (new_size == 0) { if (ifp->if_u1.if_data != ifp->if_u2.if_inline_data) { kmem_free(ifp->if_u1.if_data); } ifp->if_u1.if_data = NULL; real_size = 0; } else if (new_size <= sizeof(ifp->if_u2.if_inline_data)) { /* * If the valid extents/data can fit in if_inline_ext/data, * copy them from the malloc'd vector and free it. */ if (ifp->if_u1.if_data == NULL) { ifp->if_u1.if_data = ifp->if_u2.if_inline_data; } else if (ifp->if_u1.if_data != ifp->if_u2.if_inline_data) { ASSERT(ifp->if_real_bytes != 0); memcpy(ifp->if_u2.if_inline_data, ifp->if_u1.if_data, new_size); kmem_free(ifp->if_u1.if_data); ifp->if_u1.if_data = ifp->if_u2.if_inline_data; } real_size = 0; } else { /* * Stuck with malloc/realloc. * For inline data, the underlying buffer must be * a multiple of 4 bytes in size so that it can be * logged and stay on word boundaries. We enforce * that here. */ real_size = roundup(new_size, 4); if (ifp->if_u1.if_data == NULL) { ASSERT(ifp->if_real_bytes == 0); ifp->if_u1.if_data = kmem_alloc(real_size, KM_SLEEP | KM_NOFS); } else if (ifp->if_u1.if_data != ifp->if_u2.if_inline_data) { /* * Only do the realloc if the underlying size * is really changing. */ if (ifp->if_real_bytes != real_size) { ifp->if_u1.if_data = kmem_realloc(ifp->if_u1.if_data, real_size, ifp->if_real_bytes, KM_SLEEP | KM_NOFS); } } else { ASSERT(ifp->if_real_bytes == 0); ifp->if_u1.if_data = kmem_alloc(real_size, KM_SLEEP | KM_NOFS); memcpy(ifp->if_u1.if_data, ifp->if_u2.if_inline_data, ifp->if_bytes); } } ifp->if_real_bytes = real_size; ifp->if_bytes = new_size; ASSERT(ifp->if_bytes <= XFS_IFORK_SIZE(ip, whichfork)); } void xfs_idestroy_fork( xfs_inode_t *ip, int whichfork) { xfs_ifork_t *ifp; ifp = XFS_IFORK_PTR(ip, whichfork); if (ifp->if_broot != NULL) { kmem_free(ifp->if_broot); ifp->if_broot = NULL; } /* * If the format is local, then we can't have an extents * array so just look for an inline data array. If we're * not local then we may or may not have an extents list, * so check and free it up if we do. */ if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL) { if ((ifp->if_u1.if_data != ifp->if_u2.if_inline_data) && (ifp->if_u1.if_data != NULL)) { ASSERT(ifp->if_real_bytes != 0); kmem_free(ifp->if_u1.if_data); ifp->if_u1.if_data = NULL; ifp->if_real_bytes = 0; } } else if ((ifp->if_flags & XFS_IFEXTENTS) && ((ifp->if_flags & XFS_IFEXTIREC) || ((ifp->if_u1.if_extents != NULL) && (ifp->if_u1.if_extents != ifp->if_u2.if_inline_ext)))) { ASSERT(ifp->if_real_bytes != 0); xfs_iext_destroy(ifp); } ASSERT(ifp->if_u1.if_extents == NULL || ifp->if_u1.if_extents == ifp->if_u2.if_inline_ext); ASSERT(ifp->if_real_bytes == 0); if (whichfork == XFS_ATTR_FORK) { kmem_zone_free(xfs_ifork_zone, ip->i_afp); ip->i_afp = NULL; } } /* * Convert in-core extents to on-disk form * * For either the data or attr fork in extent format, we need to endian convert * the in-core extent as we place them into the on-disk inode. * * In the case of the data fork, the in-core and on-disk fork sizes can be * different due to delayed allocation extents. We only copy on-disk extents * here, so callers must always use the physical fork size to determine the * size of the buffer passed to this routine. We will return the size actually * used. */ int xfs_iextents_copy( xfs_inode_t *ip, xfs_bmbt_rec_t *dp, int whichfork) { int copied; int i; xfs_ifork_t *ifp; int nrecs; xfs_fsblock_t start_block; ifp = XFS_IFORK_PTR(ip, whichfork); ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_ILOCK_SHARED)); ASSERT(ifp->if_bytes > 0); nrecs = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); XFS_BMAP_TRACE_EXLIST(ip, nrecs, whichfork); ASSERT(nrecs > 0); /* * There are some delayed allocation extents in the * inode, so copy the extents one at a time and skip * the delayed ones. There must be at least one * non-delayed extent. */ copied = 0; for (i = 0; i < nrecs; i++) { xfs_bmbt_rec_host_t *ep = xfs_iext_get_ext(ifp, i); start_block = xfs_bmbt_get_startblock(ep); if (isnullstartblock(start_block)) { /* * It's a delayed allocation extent, so skip it. */ continue; } /* Translate to on disk format */ put_unaligned_be64(ep->l0, &dp->l0); put_unaligned_be64(ep->l1, &dp->l1); dp++; copied++; } ASSERT(copied != 0); xfs_validate_extents(ifp, copied, XFS_EXTFMT_INODE(ip)); return (copied * (uint)sizeof(xfs_bmbt_rec_t)); } /* * Each of the following cases stores data into the same region * of the on-disk inode, so only one of them can be valid at * any given time. While it is possible to have conflicting formats * and log flags, e.g. having XFS_ILOG_?DATA set when the fork is * in EXTENTS format, this can only happen when the fork has * changed formats after being modified but before being flushed. * In these cases, the format always takes precedence, because the * format indicates the current state of the fork. */ void xfs_iflush_fork( xfs_inode_t *ip, xfs_dinode_t *dip, xfs_inode_log_item_t *iip, int whichfork) { char *cp; xfs_ifork_t *ifp; xfs_mount_t *mp; static const short brootflag[2] = { XFS_ILOG_DBROOT, XFS_ILOG_ABROOT }; static const short dataflag[2] = { XFS_ILOG_DDATA, XFS_ILOG_ADATA }; static const short extflag[2] = { XFS_ILOG_DEXT, XFS_ILOG_AEXT }; if (!iip) return; ifp = XFS_IFORK_PTR(ip, whichfork); /* * This can happen if we gave up in iformat in an error path, * for the attribute fork. */ if (!ifp) { ASSERT(whichfork == XFS_ATTR_FORK); return; } cp = XFS_DFORK_PTR(dip, whichfork); mp = ip->i_mount; switch (XFS_IFORK_FORMAT(ip, whichfork)) { case XFS_DINODE_FMT_LOCAL: if ((iip->ili_fields & dataflag[whichfork]) && (ifp->if_bytes > 0)) { ASSERT(ifp->if_u1.if_data != NULL); ASSERT(ifp->if_bytes <= XFS_IFORK_SIZE(ip, whichfork)); memcpy(cp, ifp->if_u1.if_data, ifp->if_bytes); } break; case XFS_DINODE_FMT_EXTENTS: ASSERT((ifp->if_flags & XFS_IFEXTENTS) || !(iip->ili_fields & extflag[whichfork])); if ((iip->ili_fields & extflag[whichfork]) && (ifp->if_bytes > 0)) { ASSERT(xfs_iext_get_ext(ifp, 0)); ASSERT(XFS_IFORK_NEXTENTS(ip, whichfork) > 0); (void)xfs_iextents_copy(ip, (xfs_bmbt_rec_t *)cp, whichfork); } break; case XFS_DINODE_FMT_BTREE: if ((iip->ili_fields & brootflag[whichfork]) && (ifp->if_broot_bytes > 0)) { ASSERT(ifp->if_broot != NULL); ASSERT(XFS_BMAP_BMDR_SPACE(ifp->if_broot) <= XFS_IFORK_SIZE(ip, whichfork)); xfs_bmbt_to_bmdr(mp, ifp->if_broot, ifp->if_broot_bytes, (xfs_bmdr_block_t *)cp, XFS_DFORK_SIZE(dip, mp, whichfork)); } break; case XFS_DINODE_FMT_DEV: if (iip->ili_fields & XFS_ILOG_DEV) { ASSERT(whichfork == XFS_DATA_FORK); xfs_dinode_put_rdev(dip, ip->i_df.if_u2.if_rdev); } break; case XFS_DINODE_FMT_UUID: if (iip->ili_fields & XFS_ILOG_UUID) { ASSERT(whichfork == XFS_DATA_FORK); memcpy(XFS_DFORK_DPTR(dip), &ip->i_df.if_u2.if_uuid, sizeof(uuid_t)); } break; default: ASSERT(0); break; } } /* * Return a pointer to the extent record at file index idx. */ xfs_bmbt_rec_host_t * xfs_iext_get_ext( xfs_ifork_t *ifp, /* inode fork pointer */ xfs_extnum_t idx) /* index of target extent */ { ASSERT(idx >= 0); ASSERT(idx < ifp->if_bytes / sizeof(xfs_bmbt_rec_t)); if ((ifp->if_flags & XFS_IFEXTIREC) && (idx == 0)) { return ifp->if_u1.if_ext_irec->er_extbuf; } else if (ifp->if_flags & XFS_IFEXTIREC) { xfs_ext_irec_t *erp; /* irec pointer */ int erp_idx = 0; /* irec index */ xfs_extnum_t page_idx = idx; /* ext index in target list */ erp = xfs_iext_idx_to_irec(ifp, &page_idx, &erp_idx, 0); return &erp->er_extbuf[page_idx]; } else if (ifp->if_bytes) { return &ifp->if_u1.if_extents[idx]; } else { return NULL; } } /* * Insert new item(s) into the extent records for incore inode * fork 'ifp'. 'count' new items are inserted at index 'idx'. */ void xfs_iext_insert( xfs_inode_t *ip, /* incore inode pointer */ xfs_extnum_t idx, /* starting index of new items */ xfs_extnum_t count, /* number of inserted items */ xfs_bmbt_irec_t *new, /* items to insert */ int state) /* type of extent conversion */ { xfs_ifork_t *ifp = (state & BMAP_ATTRFORK) ? ip->i_afp : &ip->i_df; xfs_extnum_t i; /* extent record index */ trace_xfs_iext_insert(ip, idx, new, state, _RET_IP_); ASSERT(ifp->if_flags & XFS_IFEXTENTS); xfs_iext_add(ifp, idx, count); for (i = idx; i < idx + count; i++, new++) xfs_bmbt_set_all(xfs_iext_get_ext(ifp, i), new); } /* * This is called when the amount of space required for incore file * extents needs to be increased. The ext_diff parameter stores the * number of new extents being added and the idx parameter contains * the extent index where the new extents will be added. If the new * extents are being appended, then we just need to (re)allocate and * initialize the space. Otherwise, if the new extents are being * inserted into the middle of the existing entries, a bit more work * is required to make room for the new extents to be inserted. The * caller is responsible for filling in the new extent entries upon * return. */ void xfs_iext_add( xfs_ifork_t *ifp, /* inode fork pointer */ xfs_extnum_t idx, /* index to begin adding exts */ int ext_diff) /* number of extents to add */ { int byte_diff; /* new bytes being added */ int new_size; /* size of extents after adding */ xfs_extnum_t nextents; /* number of extents in file */ nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); ASSERT((idx >= 0) && (idx <= nextents)); byte_diff = ext_diff * sizeof(xfs_bmbt_rec_t); new_size = ifp->if_bytes + byte_diff; /* * If the new number of extents (nextents + ext_diff) * fits inside the inode, then continue to use the inline * extent buffer. */ if (nextents + ext_diff <= XFS_INLINE_EXTS) { if (idx < nextents) { memmove(&ifp->if_u2.if_inline_ext[idx + ext_diff], &ifp->if_u2.if_inline_ext[idx], (nextents - idx) * sizeof(xfs_bmbt_rec_t)); memset(&ifp->if_u2.if_inline_ext[idx], 0, byte_diff); } ifp->if_u1.if_extents = ifp->if_u2.if_inline_ext; ifp->if_real_bytes = 0; } /* * Otherwise use a linear (direct) extent list. * If the extents are currently inside the inode, * xfs_iext_realloc_direct will switch us from * inline to direct extent allocation mode. */ else if (nextents + ext_diff <= XFS_LINEAR_EXTS) { xfs_iext_realloc_direct(ifp, new_size); if (idx < nextents) { memmove(&ifp->if_u1.if_extents[idx + ext_diff], &ifp->if_u1.if_extents[idx], (nextents - idx) * sizeof(xfs_bmbt_rec_t)); memset(&ifp->if_u1.if_extents[idx], 0, byte_diff); } } /* Indirection array */ else { xfs_ext_irec_t *erp; int erp_idx = 0; int page_idx = idx; ASSERT(nextents + ext_diff > XFS_LINEAR_EXTS); if (ifp->if_flags & XFS_IFEXTIREC) { erp = xfs_iext_idx_to_irec(ifp, &page_idx, &erp_idx, 1); } else { xfs_iext_irec_init(ifp); ASSERT(ifp->if_flags & XFS_IFEXTIREC); erp = ifp->if_u1.if_ext_irec; } /* Extents fit in target extent page */ if (erp && erp->er_extcount + ext_diff <= XFS_LINEAR_EXTS) { if (page_idx < erp->er_extcount) { memmove(&erp->er_extbuf[page_idx + ext_diff], &erp->er_extbuf[page_idx], (erp->er_extcount - page_idx) * sizeof(xfs_bmbt_rec_t)); memset(&erp->er_extbuf[page_idx], 0, byte_diff); } erp->er_extcount += ext_diff; xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, ext_diff); } /* Insert a new extent page */ else if (erp) { xfs_iext_add_indirect_multi(ifp, erp_idx, page_idx, ext_diff); } /* * If extent(s) are being appended to the last page in * the indirection array and the new extent(s) don't fit * in the page, then erp is NULL and erp_idx is set to * the next index needed in the indirection array. */ else { uint count = ext_diff; while (count) { erp = xfs_iext_irec_new(ifp, erp_idx); erp->er_extcount = min(count, XFS_LINEAR_EXTS); count -= erp->er_extcount; if (count) erp_idx++; } } } ifp->if_bytes = new_size; } /* * This is called when incore extents are being added to the indirection * array and the new extents do not fit in the target extent list. The * erp_idx parameter contains the irec index for the target extent list * in the indirection array, and the idx parameter contains the extent * index within the list. The number of extents being added is stored * in the count parameter. * * |-------| |-------| * | | | | idx - number of extents before idx * | idx | | count | * | | | | count - number of extents being inserted at idx * |-------| |-------| * | count | | nex2 | nex2 - number of extents after idx + count * |-------| |-------| */ void xfs_iext_add_indirect_multi( xfs_ifork_t *ifp, /* inode fork pointer */ int erp_idx, /* target extent irec index */ xfs_extnum_t idx, /* index within target list */ int count) /* new extents being added */ { int byte_diff; /* new bytes being added */ xfs_ext_irec_t *erp; /* pointer to irec entry */ xfs_extnum_t ext_diff; /* number of extents to add */ xfs_extnum_t ext_cnt; /* new extents still needed */ xfs_extnum_t nex2; /* extents after idx + count */ xfs_bmbt_rec_t *nex2_ep = NULL; /* temp list for nex2 extents */ int nlists; /* number of irec's (lists) */ ASSERT(ifp->if_flags & XFS_IFEXTIREC); erp = &ifp->if_u1.if_ext_irec[erp_idx]; nex2 = erp->er_extcount - idx; nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ; /* * Save second part of target extent list * (all extents past */ if (nex2) { byte_diff = nex2 * sizeof(xfs_bmbt_rec_t); nex2_ep = (xfs_bmbt_rec_t *) kmem_alloc(byte_diff, KM_NOFS); memmove(nex2_ep, &erp->er_extbuf[idx], byte_diff); erp->er_extcount -= nex2; xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, -nex2); memset(&erp->er_extbuf[idx], 0, byte_diff); } /* * Add the new extents to the end of the target * list, then allocate new irec record(s) and * extent buffer(s) as needed to store the rest * of the new extents. */ ext_cnt = count; ext_diff = MIN(ext_cnt, (int)XFS_LINEAR_EXTS - erp->er_extcount); if (ext_diff) { erp->er_extcount += ext_diff; xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, ext_diff); ext_cnt -= ext_diff; } while (ext_cnt) { erp_idx++; erp = xfs_iext_irec_new(ifp, erp_idx); ext_diff = MIN(ext_cnt, (int)XFS_LINEAR_EXTS); erp->er_extcount = ext_diff; xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, ext_diff); ext_cnt -= ext_diff; } /* Add nex2 extents back to indirection array */ if (nex2) { xfs_extnum_t ext_avail; int i; byte_diff = nex2 * sizeof(xfs_bmbt_rec_t); ext_avail = XFS_LINEAR_EXTS - erp->er_extcount; i = 0; /* * If nex2 extents fit in the current page, append * nex2_ep after the new extents. */ if (nex2 <= ext_avail) { i = erp->er_extcount; } /* * Otherwise, check if space is available in the * next page. */ else if ((erp_idx < nlists - 1) && (nex2 <= (ext_avail = XFS_LINEAR_EXTS - ifp->if_u1.if_ext_irec[erp_idx+1].er_extcount))) { erp_idx++; erp++; /* Create a hole for nex2 extents */ memmove(&erp->er_extbuf[nex2], erp->er_extbuf, erp->er_extcount * sizeof(xfs_bmbt_rec_t)); } /* * Final choice, create a new extent page for * nex2 extents. */ else { erp_idx++; erp = xfs_iext_irec_new(ifp, erp_idx); } memmove(&erp->er_extbuf[i], nex2_ep, byte_diff); kmem_free(nex2_ep); erp->er_extcount += nex2; xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, nex2); } } /* * This is called when the amount of space required for incore file * extents needs to be decreased. The ext_diff parameter stores the * number of extents to be removed and the idx parameter contains * the extent index where the extents will be removed from. * * If the amount of space needed has decreased below the linear * limit, XFS_IEXT_BUFSZ, then switch to using the contiguous * extent array. Otherwise, use kmem_realloc() to adjust the * size to what is needed. */ void xfs_iext_remove( xfs_inode_t *ip, /* incore inode pointer */ xfs_extnum_t idx, /* index to begin removing exts */ int ext_diff, /* number of extents to remove */ int state) /* type of extent conversion */ { xfs_ifork_t *ifp = (state & BMAP_ATTRFORK) ? ip->i_afp : &ip->i_df; xfs_extnum_t nextents; /* number of extents in file */ int new_size; /* size of extents after removal */ trace_xfs_iext_remove(ip, idx, state, _RET_IP_); ASSERT(ext_diff > 0); nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); new_size = (nextents - ext_diff) * sizeof(xfs_bmbt_rec_t); if (new_size == 0) { xfs_iext_destroy(ifp); } else if (ifp->if_flags & XFS_IFEXTIREC) { xfs_iext_remove_indirect(ifp, idx, ext_diff); } else if (ifp->if_real_bytes) { xfs_iext_remove_direct(ifp, idx, ext_diff); } else { xfs_iext_remove_inline(ifp, idx, ext_diff); } ifp->if_bytes = new_size; } /* * This removes ext_diff extents from the inline buffer, beginning * at extent index idx. */ void xfs_iext_remove_inline( xfs_ifork_t *ifp, /* inode fork pointer */ xfs_extnum_t idx, /* index to begin removing exts */ int ext_diff) /* number of extents to remove */ { int nextents; /* number of extents in file */ ASSERT(!(ifp->if_flags & XFS_IFEXTIREC)); ASSERT(idx < XFS_INLINE_EXTS); nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); ASSERT(((nextents - ext_diff) > 0) && (nextents - ext_diff) < XFS_INLINE_EXTS); if (idx + ext_diff < nextents) { memmove(&ifp->if_u2.if_inline_ext[idx], &ifp->if_u2.if_inline_ext[idx + ext_diff], (nextents - (idx + ext_diff)) * sizeof(xfs_bmbt_rec_t)); memset(&ifp->if_u2.if_inline_ext[nextents - ext_diff], 0, ext_diff * sizeof(xfs_bmbt_rec_t)); } else { memset(&ifp->if_u2.if_inline_ext[idx], 0, ext_diff * sizeof(xfs_bmbt_rec_t)); } } /* * This removes ext_diff extents from a linear (direct) extent list, * beginning at extent index idx. If the extents are being removed * from the end of the list (ie. truncate) then we just need to re- * allocate the list to remove the extra space. Otherwise, if the * extents are being removed from the middle of the existing extent * entries, then we first need to move the extent records beginning * at idx + ext_diff up in the list to overwrite the records being * removed, then remove the extra space via kmem_realloc. */ void xfs_iext_remove_direct( xfs_ifork_t *ifp, /* inode fork pointer */ xfs_extnum_t idx, /* index to begin removing exts */ int ext_diff) /* number of extents to remove */ { xfs_extnum_t nextents; /* number of extents in file */ int new_size; /* size of extents after removal */ ASSERT(!(ifp->if_flags & XFS_IFEXTIREC)); new_size = ifp->if_bytes - (ext_diff * sizeof(xfs_bmbt_rec_t)); nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); if (new_size == 0) { xfs_iext_destroy(ifp); return; } /* Move extents up in the list (if needed) */ if (idx + ext_diff < nextents) { memmove(&ifp->if_u1.if_extents[idx], &ifp->if_u1.if_extents[idx + ext_diff], (nextents - (idx + ext_diff)) * sizeof(xfs_bmbt_rec_t)); } memset(&ifp->if_u1.if_extents[nextents - ext_diff], 0, ext_diff * sizeof(xfs_bmbt_rec_t)); /* * Reallocate the direct extent list. If the extents * will fit inside the inode then xfs_iext_realloc_direct * will switch from direct to inline extent allocation * mode for us. */ xfs_iext_realloc_direct(ifp, new_size); ifp->if_bytes = new_size; } /* * This is called when incore extents are being removed from the * indirection array and the extents being removed span multiple extent * buffers. The idx parameter contains the file extent index where we * want to begin removing extents, and the count parameter contains * how many extents need to be removed. * * |-------| |-------| * | nex1 | | | nex1 - number of extents before idx * |-------| | count | * | | | | count - number of extents being removed at idx * | count | |-------| * | | | nex2 | nex2 - number of extents after idx + count * |-------| |-------| */ void xfs_iext_remove_indirect( xfs_ifork_t *ifp, /* inode fork pointer */ xfs_extnum_t idx, /* index to begin removing extents */ int count) /* number of extents to remove */ { xfs_ext_irec_t *erp; /* indirection array pointer */ int erp_idx = 0; /* indirection array index */ xfs_extnum_t ext_cnt; /* extents left to remove */ xfs_extnum_t ext_diff; /* extents to remove in current list */ xfs_extnum_t nex1; /* number of extents before idx */ xfs_extnum_t nex2; /* extents after idx + count */ int page_idx = idx; /* index in target extent list */ ASSERT(ifp->if_flags & XFS_IFEXTIREC); erp = xfs_iext_idx_to_irec(ifp, &page_idx, &erp_idx, 0); ASSERT(erp != NULL); nex1 = page_idx; ext_cnt = count; while (ext_cnt) { nex2 = MAX((erp->er_extcount - (nex1 + ext_cnt)), 0); ext_diff = MIN(ext_cnt, (erp->er_extcount - nex1)); /* * Check for deletion of entire list; * xfs_iext_irec_remove() updates extent offsets. */ if (ext_diff == erp->er_extcount) { xfs_iext_irec_remove(ifp, erp_idx); ext_cnt -= ext_diff; nex1 = 0; if (ext_cnt) { ASSERT(erp_idx < ifp->if_real_bytes / XFS_IEXT_BUFSZ); erp = &ifp->if_u1.if_ext_irec[erp_idx]; nex1 = 0; continue; } else { break; } } /* Move extents up (if needed) */ if (nex2) { memmove(&erp->er_extbuf[nex1], &erp->er_extbuf[nex1 + ext_diff], nex2 * sizeof(xfs_bmbt_rec_t)); } /* Zero out rest of page */ memset(&erp->er_extbuf[nex1 + nex2], 0, (XFS_IEXT_BUFSZ - ((nex1 + nex2) * sizeof(xfs_bmbt_rec_t)))); /* Update remaining counters */ erp->er_extcount -= ext_diff; xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, -ext_diff); ext_cnt -= ext_diff; nex1 = 0; erp_idx++; erp++; } ifp->if_bytes -= count * sizeof(xfs_bmbt_rec_t); xfs_iext_irec_compact(ifp); } /* * Create, destroy, or resize a linear (direct) block of extents. */ void xfs_iext_realloc_direct( xfs_ifork_t *ifp, /* inode fork pointer */ int new_size) /* new size of extents after adding */ { int rnew_size; /* real new size of extents */ rnew_size = new_size; ASSERT(!(ifp->if_flags & XFS_IFEXTIREC) || ((new_size >= 0) && (new_size <= XFS_IEXT_BUFSZ) && (new_size != ifp->if_real_bytes))); /* Free extent records */ if (new_size == 0) { xfs_iext_destroy(ifp); } /* Resize direct extent list and zero any new bytes */ else if (ifp->if_real_bytes) { /* Check if extents will fit inside the inode */ if (new_size <= XFS_INLINE_EXTS * sizeof(xfs_bmbt_rec_t)) { xfs_iext_direct_to_inline(ifp, new_size / (uint)sizeof(xfs_bmbt_rec_t)); ifp->if_bytes = new_size; return; } if (!is_power_of_2(new_size)){ rnew_size = roundup_pow_of_two(new_size); } if (rnew_size != ifp->if_real_bytes) { ifp->if_u1.if_extents = kmem_realloc(ifp->if_u1.if_extents, rnew_size, ifp->if_real_bytes, KM_NOFS); } if (rnew_size > ifp->if_real_bytes) { memset(&ifp->if_u1.if_extents[ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t)], 0, rnew_size - ifp->if_real_bytes); } } /* Switch from the inline extent buffer to a direct extent list */ else { if (!is_power_of_2(new_size)) { rnew_size = roundup_pow_of_two(new_size); } xfs_iext_inline_to_direct(ifp, rnew_size); } ifp->if_real_bytes = rnew_size; ifp->if_bytes = new_size; } /* * Switch from linear (direct) extent records to inline buffer. */ void xfs_iext_direct_to_inline( xfs_ifork_t *ifp, /* inode fork pointer */ xfs_extnum_t nextents) /* number of extents in file */ { ASSERT(ifp->if_flags & XFS_IFEXTENTS); ASSERT(nextents <= XFS_INLINE_EXTS); /* * The inline buffer was zeroed when we switched * from inline to direct extent allocation mode, * so we don't need to clear it here. */ memcpy(ifp->if_u2.if_inline_ext, ifp->if_u1.if_extents, nextents * sizeof(xfs_bmbt_rec_t)); kmem_free(ifp->if_u1.if_extents); ifp->if_u1.if_extents = ifp->if_u2.if_inline_ext; ifp->if_real_bytes = 0; } /* * Switch from inline buffer to linear (direct) extent records. * new_size should already be rounded up to the next power of 2 * by the caller (when appropriate), so use new_size as it is. * However, since new_size may be rounded up, we can't update * if_bytes here. It is the caller's responsibility to update * if_bytes upon return. */ void xfs_iext_inline_to_direct( xfs_ifork_t *ifp, /* inode fork pointer */ int new_size) /* number of extents in file */ { ifp->if_u1.if_extents = kmem_alloc(new_size, KM_NOFS); memset(ifp->if_u1.if_extents, 0, new_size); if (ifp->if_bytes) { memcpy(ifp->if_u1.if_extents, ifp->if_u2.if_inline_ext, ifp->if_bytes); memset(ifp->if_u2.if_inline_ext, 0, XFS_INLINE_EXTS * sizeof(xfs_bmbt_rec_t)); } ifp->if_real_bytes = new_size; } /* * Resize an extent indirection array to new_size bytes. */ STATIC void xfs_iext_realloc_indirect( xfs_ifork_t *ifp, /* inode fork pointer */ int new_size) /* new indirection array size */ { int nlists; /* number of irec's (ex lists) */ int size; /* current indirection array size */ ASSERT(ifp->if_flags & XFS_IFEXTIREC); nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ; size = nlists * sizeof(xfs_ext_irec_t); ASSERT(ifp->if_real_bytes); ASSERT((new_size >= 0) && (new_size != size)); if (new_size == 0) { xfs_iext_destroy(ifp); } else { ifp->if_u1.if_ext_irec = (xfs_ext_irec_t *) kmem_realloc(ifp->if_u1.if_ext_irec, new_size, size, KM_NOFS); } } /* * Switch from indirection array to linear (direct) extent allocations. */ STATIC void xfs_iext_indirect_to_direct( xfs_ifork_t *ifp) /* inode fork pointer */ { xfs_bmbt_rec_host_t *ep; /* extent record pointer */ xfs_extnum_t nextents; /* number of extents in file */ int size; /* size of file extents */ ASSERT(ifp->if_flags & XFS_IFEXTIREC); nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); ASSERT(nextents <= XFS_LINEAR_EXTS); size = nextents * sizeof(xfs_bmbt_rec_t); xfs_iext_irec_compact_pages(ifp); ASSERT(ifp->if_real_bytes == XFS_IEXT_BUFSZ); ep = ifp->if_u1.if_ext_irec->er_extbuf; kmem_free(ifp->if_u1.if_ext_irec); ifp->if_flags &= ~XFS_IFEXTIREC; ifp->if_u1.if_extents = ep; ifp->if_bytes = size; if (nextents < XFS_LINEAR_EXTS) { xfs_iext_realloc_direct(ifp, size); } } /* * Free incore file extents. */ void xfs_iext_destroy( xfs_ifork_t *ifp) /* inode fork pointer */ { if (ifp->if_flags & XFS_IFEXTIREC) { int erp_idx; int nlists; nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ; for (erp_idx = nlists - 1; erp_idx >= 0 ; erp_idx--) { xfs_iext_irec_remove(ifp, erp_idx); } ifp->if_flags &= ~XFS_IFEXTIREC; } else if (ifp->if_real_bytes) { kmem_free(ifp->if_u1.if_extents); } else if (ifp->if_bytes) { memset(ifp->if_u2.if_inline_ext, 0, XFS_INLINE_EXTS * sizeof(xfs_bmbt_rec_t)); } ifp->if_u1.if_extents = NULL; ifp->if_real_bytes = 0; ifp->if_bytes = 0; } /* * Return a pointer to the extent record for file system block bno. */ xfs_bmbt_rec_host_t * /* pointer to found extent record */ xfs_iext_bno_to_ext( xfs_ifork_t *ifp, /* inode fork pointer */ xfs_fileoff_t bno, /* block number to search for */ xfs_extnum_t *idxp) /* index of target extent */ { xfs_bmbt_rec_host_t *base; /* pointer to first extent */ xfs_filblks_t blockcount = 0; /* number of blocks in extent */ xfs_bmbt_rec_host_t *ep = NULL; /* pointer to target extent */ xfs_ext_irec_t *erp = NULL; /* indirection array pointer */ int high; /* upper boundary in search */ xfs_extnum_t idx = 0; /* index of target extent */ int low; /* lower boundary in search */ xfs_extnum_t nextents; /* number of file extents */ xfs_fileoff_t startoff = 0; /* start offset of extent */ nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); if (nextents == 0) { *idxp = 0; return NULL; } low = 0; if (ifp->if_flags & XFS_IFEXTIREC) { /* Find target extent list */ int erp_idx = 0; erp = xfs_iext_bno_to_irec(ifp, bno, &erp_idx); base = erp->er_extbuf; high = erp->er_extcount - 1; } else { base = ifp->if_u1.if_extents; high = nextents - 1; } /* Binary search extent records */ while (low <= high) { idx = (low + high) >> 1; ep = base + idx; startoff = xfs_bmbt_get_startoff(ep); blockcount = xfs_bmbt_get_blockcount(ep); if (bno < startoff) { high = idx - 1; } else if (bno >= startoff + blockcount) { low = idx + 1; } else { /* Convert back to file-based extent index */ if (ifp->if_flags & XFS_IFEXTIREC) { idx += erp->er_extoff; } *idxp = idx; return ep; } } /* Convert back to file-based extent index */ if (ifp->if_flags & XFS_IFEXTIREC) { idx += erp->er_extoff; } if (bno >= startoff + blockcount) { if (++idx == nextents) { ep = NULL; } else { ep = xfs_iext_get_ext(ifp, idx); } } *idxp = idx; return ep; } /* * Return a pointer to the indirection array entry containing the * extent record for filesystem block bno. Store the index of the * target irec in *erp_idxp. */ xfs_ext_irec_t * /* pointer to found extent record */ xfs_iext_bno_to_irec( xfs_ifork_t *ifp, /* inode fork pointer */ xfs_fileoff_t bno, /* block number to search for */ int *erp_idxp) /* irec index of target ext list */ { xfs_ext_irec_t *erp = NULL; /* indirection array pointer */ xfs_ext_irec_t *erp_next; /* next indirection array entry */ int erp_idx; /* indirection array index */ int nlists; /* number of extent irec's (lists) */ int high; /* binary search upper limit */ int low; /* binary search lower limit */ ASSERT(ifp->if_flags & XFS_IFEXTIREC); nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ; erp_idx = 0; low = 0; high = nlists - 1; while (low <= high) { erp_idx = (low + high) >> 1; erp = &ifp->if_u1.if_ext_irec[erp_idx]; erp_next = erp_idx < nlists - 1 ? erp + 1 : NULL; if (bno < xfs_bmbt_get_startoff(erp->er_extbuf)) { high = erp_idx - 1; } else if (erp_next && bno >= xfs_bmbt_get_startoff(erp_next->er_extbuf)) { low = erp_idx + 1; } else { break; } } *erp_idxp = erp_idx; return erp; } /* * Return a pointer to the indirection array entry containing the * extent record at file extent index *idxp. Store the index of the * target irec in *erp_idxp and store the page index of the target * extent record in *idxp. */ xfs_ext_irec_t * xfs_iext_idx_to_irec( xfs_ifork_t *ifp, /* inode fork pointer */ xfs_extnum_t *idxp, /* extent index (file -> page) */ int *erp_idxp, /* pointer to target irec */ int realloc) /* new bytes were just added */ { xfs_ext_irec_t *prev; /* pointer to previous irec */ xfs_ext_irec_t *erp = NULL; /* pointer to current irec */ int erp_idx; /* indirection array index */ int nlists; /* number of irec's (ex lists) */ int high; /* binary search upper limit */ int low; /* binary search lower limit */ xfs_extnum_t page_idx = *idxp; /* extent index in target list */ ASSERT(ifp->if_flags & XFS_IFEXTIREC); ASSERT(page_idx >= 0); ASSERT(page_idx <= ifp->if_bytes / sizeof(xfs_bmbt_rec_t)); ASSERT(page_idx < ifp->if_bytes / sizeof(xfs_bmbt_rec_t) || realloc); nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ; erp_idx = 0; low = 0; high = nlists - 1; /* Binary search extent irec's */ while (low <= high) { erp_idx = (low + high) >> 1; erp = &ifp->if_u1.if_ext_irec[erp_idx]; prev = erp_idx > 0 ? erp - 1 : NULL; if (page_idx < erp->er_extoff || (page_idx == erp->er_extoff && realloc && prev && prev->er_extcount < XFS_LINEAR_EXTS)) { high = erp_idx - 1; } else if (page_idx > erp->er_extoff + erp->er_extcount || (page_idx == erp->er_extoff + erp->er_extcount && !realloc)) { low = erp_idx + 1; } else if (page_idx == erp->er_extoff + erp->er_extcount && erp->er_extcount == XFS_LINEAR_EXTS) { ASSERT(realloc); page_idx = 0; erp_idx++; erp = erp_idx < nlists ? erp + 1 : NULL; break; } else { page_idx -= erp->er_extoff; break; } } *idxp = page_idx; *erp_idxp = erp_idx; return erp; } /* * Allocate and initialize an indirection array once the space needed * for incore extents increases above XFS_IEXT_BUFSZ. */ void xfs_iext_irec_init( xfs_ifork_t *ifp) /* inode fork pointer */ { xfs_ext_irec_t *erp; /* indirection array pointer */ xfs_extnum_t nextents; /* number of extents in file */ ASSERT(!(ifp->if_flags & XFS_IFEXTIREC)); nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); ASSERT(nextents <= XFS_LINEAR_EXTS); erp = kmem_alloc(sizeof(xfs_ext_irec_t), KM_NOFS); if (nextents == 0) { ifp->if_u1.if_extents = kmem_alloc(XFS_IEXT_BUFSZ, KM_NOFS); } else if (!ifp->if_real_bytes) { xfs_iext_inline_to_direct(ifp, XFS_IEXT_BUFSZ); } else if (ifp->if_real_bytes < XFS_IEXT_BUFSZ) { xfs_iext_realloc_direct(ifp, XFS_IEXT_BUFSZ); } erp->er_extbuf = ifp->if_u1.if_extents; erp->er_extcount = nextents; erp->er_extoff = 0; ifp->if_flags |= XFS_IFEXTIREC; ifp->if_real_bytes = XFS_IEXT_BUFSZ; ifp->if_bytes = nextents * sizeof(xfs_bmbt_rec_t); ifp->if_u1.if_ext_irec = erp; return; } /* * Allocate and initialize a new entry in the indirection array. */ xfs_ext_irec_t * xfs_iext_irec_new( xfs_ifork_t *ifp, /* inode fork pointer */ int erp_idx) /* index for new irec */ { xfs_ext_irec_t *erp; /* indirection array pointer */ int i; /* loop counter */ int nlists; /* number of irec's (ex lists) */ ASSERT(ifp->if_flags & XFS_IFEXTIREC); nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ; /* Resize indirection array */ xfs_iext_realloc_indirect(ifp, ++nlists * sizeof(xfs_ext_irec_t)); /* * Move records down in the array so the * new page can use erp_idx. */ erp = ifp->if_u1.if_ext_irec; for (i = nlists - 1; i > erp_idx; i--) { memmove(&erp[i], &erp[i-1], sizeof(xfs_ext_irec_t)); } ASSERT(i == erp_idx); /* Initialize new extent record */ erp = ifp->if_u1.if_ext_irec; erp[erp_idx].er_extbuf = kmem_alloc(XFS_IEXT_BUFSZ, KM_NOFS); ifp->if_real_bytes = nlists * XFS_IEXT_BUFSZ; memset(erp[erp_idx].er_extbuf, 0, XFS_IEXT_BUFSZ); erp[erp_idx].er_extcount = 0; erp[erp_idx].er_extoff = erp_idx > 0 ? erp[erp_idx-1].er_extoff + erp[erp_idx-1].er_extcount : 0; return (&erp[erp_idx]); } /* * Remove a record from the indirection array. */ void xfs_iext_irec_remove( xfs_ifork_t *ifp, /* inode fork pointer */ int erp_idx) /* irec index to remove */ { xfs_ext_irec_t *erp; /* indirection array pointer */ int i; /* loop counter */ int nlists; /* number of irec's (ex lists) */ ASSERT(ifp->if_flags & XFS_IFEXTIREC); nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ; erp = &ifp->if_u1.if_ext_irec[erp_idx]; if (erp->er_extbuf) { xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, -erp->er_extcount); kmem_free(erp->er_extbuf); } /* Compact extent records */ erp = ifp->if_u1.if_ext_irec; for (i = erp_idx; i < nlists - 1; i++) { memmove(&erp[i], &erp[i+1], sizeof(xfs_ext_irec_t)); } /* * Manually free the last extent record from the indirection * array. A call to xfs_iext_realloc_indirect() with a size * of zero would result in a call to xfs_iext_destroy() which * would in turn call this function again, creating a nasty * infinite loop. */ if (--nlists) { xfs_iext_realloc_indirect(ifp, nlists * sizeof(xfs_ext_irec_t)); } else { kmem_free(ifp->if_u1.if_ext_irec); } ifp->if_real_bytes = nlists * XFS_IEXT_BUFSZ; } /* * This is called to clean up large amounts of unused memory allocated * by the indirection array. Before compacting anything though, verify * that the indirection array is still needed and switch back to the * linear extent list (or even the inline buffer) if possible. The * compaction policy is as follows: * * Full Compaction: Extents fit into a single page (or inline buffer) * Partial Compaction: Extents occupy less than 50% of allocated space * No Compaction: Extents occupy at least 50% of allocated space */ void xfs_iext_irec_compact( xfs_ifork_t *ifp) /* inode fork pointer */ { xfs_extnum_t nextents; /* number of extents in file */ int nlists; /* number of irec's (ex lists) */ ASSERT(ifp->if_flags & XFS_IFEXTIREC); nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ; nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); if (nextents == 0) { xfs_iext_destroy(ifp); } else if (nextents <= XFS_INLINE_EXTS) { xfs_iext_indirect_to_direct(ifp); xfs_iext_direct_to_inline(ifp, nextents); } else if (nextents <= XFS_LINEAR_EXTS) { xfs_iext_indirect_to_direct(ifp); } else if (nextents < (nlists * XFS_LINEAR_EXTS) >> 1) { xfs_iext_irec_compact_pages(ifp); } } /* * Combine extents from neighboring extent pages. */ void xfs_iext_irec_compact_pages( xfs_ifork_t *ifp) /* inode fork pointer */ { xfs_ext_irec_t *erp, *erp_next;/* pointers to irec entries */ int erp_idx = 0; /* indirection array index */ int nlists; /* number of irec's (ex lists) */ ASSERT(ifp->if_flags & XFS_IFEXTIREC); nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ; while (erp_idx < nlists - 1) { erp = &ifp->if_u1.if_ext_irec[erp_idx]; erp_next = erp + 1; if (erp_next->er_extcount <= (XFS_LINEAR_EXTS - erp->er_extcount)) { memcpy(&erp->er_extbuf[erp->er_extcount], erp_next->er_extbuf, erp_next->er_extcount * sizeof(xfs_bmbt_rec_t)); erp->er_extcount += erp_next->er_extcount; /* * Free page before removing extent record * so er_extoffs don't get modified in * xfs_iext_irec_remove. */ kmem_free(erp_next->er_extbuf); erp_next->er_extbuf = NULL; xfs_iext_irec_remove(ifp, erp_idx + 1); nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ; } else { erp_idx++; } } } /* * This is called to update the er_extoff field in the indirection * array when extents have been added or removed from one of the * extent lists. erp_idx contains the irec index to begin updating * at and ext_diff contains the number of extents that were added * or removed. */ void xfs_iext_irec_update_extoffs( xfs_ifork_t *ifp, /* inode fork pointer */ int erp_idx, /* irec index to update */ int ext_diff) /* number of new extents */ { int i; /* loop counter */ int nlists; /* number of irec's (ex lists */ ASSERT(ifp->if_flags & XFS_IFEXTIREC); nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ; for (i = erp_idx; i < nlists; i++) { ifp->if_u1.if_ext_irec[i].er_extoff += ext_diff; } } partclone-0.2.86/src/xfs/xfs_inode_fork.h000066400000000000000000000151201262102574200203350ustar00rootroot00000000000000/* * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __XFS_INODE_FORK_H__ #define __XFS_INODE_FORK_H__ struct xfs_inode_log_item; struct xfs_dinode; /* * The following xfs_ext_irec_t struct introduces a second (top) level * to the in-core extent allocation scheme. These structs are allocated * in a contiguous block, creating an indirection array where each entry * (irec) contains a pointer to a buffer of in-core extent records which * it manages. Each extent buffer is 4k in size, since 4k is the system * page size on Linux i386 and systems with larger page sizes don't seem * to gain much, if anything, by using their native page size as the * extent buffer size. Also, using 4k extent buffers everywhere provides * a consistent interface for CXFS across different platforms. * * There is currently no limit on the number of irec's (extent lists) * allowed, so heavily fragmented files may require an indirection array * which spans multiple system pages of memory. The number of extents * which would require this amount of contiguous memory is very large * and should not cause problems in the foreseeable future. However, * if the memory needed for the contiguous array ever becomes a problem, * it is possible that a third level of indirection may be required. */ typedef struct xfs_ext_irec { xfs_bmbt_rec_host_t *er_extbuf; /* block of extent records */ xfs_extnum_t er_extoff; /* extent offset in file */ xfs_extnum_t er_extcount; /* number of extents in page/block */ } xfs_ext_irec_t; /* * File incore extent information, present for each of data & attr forks. */ #define XFS_IEXT_BUFSZ 4096 #define XFS_LINEAR_EXTS (XFS_IEXT_BUFSZ / (uint)sizeof(xfs_bmbt_rec_t)) #define XFS_INLINE_EXTS 2 #define XFS_INLINE_DATA 32 typedef struct xfs_ifork { int if_bytes; /* bytes in if_u1 */ int if_real_bytes; /* bytes allocated in if_u1 */ struct xfs_btree_block *if_broot; /* file's incore btree root */ short if_broot_bytes; /* bytes allocated for root */ unsigned char if_flags; /* per-fork flags */ union { xfs_bmbt_rec_host_t *if_extents;/* linear map file exts */ xfs_ext_irec_t *if_ext_irec; /* irec map file exts */ char *if_data; /* inline file data */ } if_u1; union { xfs_bmbt_rec_host_t if_inline_ext[XFS_INLINE_EXTS]; /* very small file extents */ char if_inline_data[XFS_INLINE_DATA]; /* very small file data */ xfs_dev_t if_rdev; /* dev number if special */ uuid_t if_uuid; /* mount point value */ } if_u2; } xfs_ifork_t; /* * Per-fork incore inode flags. */ #define XFS_IFINLINE 0x01 /* Inline data is read in */ #define XFS_IFEXTENTS 0x02 /* All extent pointers are read in */ #define XFS_IFBROOT 0x04 /* i_broot points to the bmap b-tree root */ #define XFS_IFEXTIREC 0x08 /* Indirection array of extent blocks */ /* * Fork handling. */ #define XFS_IFORK_Q(ip) ((ip)->i_d.di_forkoff != 0) #define XFS_IFORK_BOFF(ip) ((int)((ip)->i_d.di_forkoff << 3)) #define XFS_IFORK_PTR(ip,w) \ ((w) == XFS_DATA_FORK ? \ &(ip)->i_df : \ (ip)->i_afp) #define XFS_IFORK_DSIZE(ip) \ (XFS_IFORK_Q(ip) ? \ XFS_IFORK_BOFF(ip) : \ XFS_LITINO((ip)->i_mount, (ip)->i_d.di_version)) #define XFS_IFORK_ASIZE(ip) \ (XFS_IFORK_Q(ip) ? \ XFS_LITINO((ip)->i_mount, (ip)->i_d.di_version) - \ XFS_IFORK_BOFF(ip) : \ 0) #define XFS_IFORK_SIZE(ip,w) \ ((w) == XFS_DATA_FORK ? \ XFS_IFORK_DSIZE(ip) : \ XFS_IFORK_ASIZE(ip)) #define XFS_IFORK_FORMAT(ip,w) \ ((w) == XFS_DATA_FORK ? \ (ip)->i_d.di_format : \ (ip)->i_d.di_aformat) #define XFS_IFORK_FMT_SET(ip,w,n) \ ((w) == XFS_DATA_FORK ? \ ((ip)->i_d.di_format = (n)) : \ ((ip)->i_d.di_aformat = (n))) #define XFS_IFORK_NEXTENTS(ip,w) \ ((w) == XFS_DATA_FORK ? \ (ip)->i_d.di_nextents : \ (ip)->i_d.di_anextents) #define XFS_IFORK_NEXT_SET(ip,w,n) \ ((w) == XFS_DATA_FORK ? \ ((ip)->i_d.di_nextents = (n)) : \ ((ip)->i_d.di_anextents = (n))) #define XFS_IFORK_MAXEXT(ip, w) \ (XFS_IFORK_SIZE(ip, w) / sizeof(xfs_bmbt_rec_t)) int xfs_iformat_fork(struct xfs_inode *, struct xfs_dinode *); void xfs_iflush_fork(struct xfs_inode *, struct xfs_dinode *, struct xfs_inode_log_item *, int); void xfs_idestroy_fork(struct xfs_inode *, int); void xfs_idata_realloc(struct xfs_inode *, int, int); void xfs_iroot_realloc(struct xfs_inode *, int, int); int xfs_iread_extents(struct xfs_trans *, struct xfs_inode *, int); int xfs_iextents_copy(struct xfs_inode *, struct xfs_bmbt_rec *, int); struct xfs_bmbt_rec_host * xfs_iext_get_ext(struct xfs_ifork *, xfs_extnum_t); void xfs_iext_insert(struct xfs_inode *, xfs_extnum_t, xfs_extnum_t, struct xfs_bmbt_irec *, int); void xfs_iext_add(struct xfs_ifork *, xfs_extnum_t, int); void xfs_iext_add_indirect_multi(struct xfs_ifork *, int, xfs_extnum_t, int); void xfs_iext_remove(struct xfs_inode *, xfs_extnum_t, int, int); void xfs_iext_remove_inline(struct xfs_ifork *, xfs_extnum_t, int); void xfs_iext_remove_direct(struct xfs_ifork *, xfs_extnum_t, int); void xfs_iext_remove_indirect(struct xfs_ifork *, xfs_extnum_t, int); void xfs_iext_realloc_direct(struct xfs_ifork *, int); void xfs_iext_direct_to_inline(struct xfs_ifork *, xfs_extnum_t); void xfs_iext_inline_to_direct(struct xfs_ifork *, int); void xfs_iext_destroy(struct xfs_ifork *); struct xfs_bmbt_rec_host * xfs_iext_bno_to_ext(struct xfs_ifork *, xfs_fileoff_t, int *); struct xfs_ext_irec * xfs_iext_bno_to_irec(struct xfs_ifork *, xfs_fileoff_t, int *); struct xfs_ext_irec * xfs_iext_idx_to_irec(struct xfs_ifork *, xfs_extnum_t *, int *, int); void xfs_iext_irec_init(struct xfs_ifork *); struct xfs_ext_irec * xfs_iext_irec_new(struct xfs_ifork *, int); void xfs_iext_irec_remove(struct xfs_ifork *, int); void xfs_iext_irec_compact(struct xfs_ifork *); void xfs_iext_irec_compact_pages(struct xfs_ifork *); void xfs_iext_irec_compact_full(struct xfs_ifork *); void xfs_iext_irec_update_extoffs(struct xfs_ifork *, int, int); extern struct kmem_zone *xfs_ifork_zone; #endif /* __XFS_INODE_FORK_H__ */ partclone-0.2.86/src/xfs/xfs_log_format.h000066400000000000000000000600041262102574200203500ustar00rootroot00000000000000/* * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __XFS_LOG_FORMAT_H__ #define __XFS_LOG_FORMAT_H__ struct xfs_mount; struct xfs_trans_res; /* * On-disk Log Format definitions. * * This file contains all the on-disk format definitions used within the log. It * includes the physical log structure itself, as well as all the log item * format structures that are written into the log and intepreted by log * recovery. We start with the physical log format definitions, and then work * through all the log items definitions and everything they encode into the * log. */ typedef __uint32_t xlog_tid_t; #define XLOG_MIN_ICLOGS 2 #define XLOG_MAX_ICLOGS 8 #define XLOG_HEADER_MAGIC_NUM 0xFEEDbabe /* Invalid cycle number */ #define XLOG_VERSION_1 1 #define XLOG_VERSION_2 2 /* Large IClogs, Log sunit */ #define XLOG_VERSION_OKBITS (XLOG_VERSION_1 | XLOG_VERSION_2) #define XLOG_MIN_RECORD_BSIZE (16*1024) /* eventually 32k */ #define XLOG_BIG_RECORD_BSIZE (32*1024) /* 32k buffers */ #define XLOG_MAX_RECORD_BSIZE (256*1024) #define XLOG_HEADER_CYCLE_SIZE (32*1024) /* cycle data in header */ #define XLOG_MIN_RECORD_BSHIFT 14 /* 16384 == 1 << 14 */ #define XLOG_BIG_RECORD_BSHIFT 15 /* 32k == 1 << 15 */ #define XLOG_MAX_RECORD_BSHIFT 18 /* 256k == 1 << 18 */ #define XLOG_BTOLSUNIT(log, b) (((b)+(log)->l_mp->m_sb.sb_logsunit-1) / \ (log)->l_mp->m_sb.sb_logsunit) #define XLOG_LSUNITTOB(log, su) ((su) * (log)->l_mp->m_sb.sb_logsunit) #define XLOG_HEADER_SIZE 512 /* Minimum number of transactions that must fit in the log (defined by mkfs) */ #define XFS_MIN_LOG_FACTOR 3 #define XLOG_REC_SHIFT(log) \ BTOBB(1 << (xfs_sb_version_haslogv2(&log->l_mp->m_sb) ? \ XLOG_MAX_RECORD_BSHIFT : XLOG_BIG_RECORD_BSHIFT)) #define XLOG_TOTAL_REC_SHIFT(log) \ BTOBB(XLOG_MAX_ICLOGS << (xfs_sb_version_haslogv2(&log->l_mp->m_sb) ? \ XLOG_MAX_RECORD_BSHIFT : XLOG_BIG_RECORD_BSHIFT)) /* get lsn fields */ #define CYCLE_LSN(lsn) ((uint)((lsn)>>32)) #define BLOCK_LSN(lsn) ((uint)(lsn)) /* this is used in a spot where we might otherwise double-endian-flip */ #define CYCLE_LSN_DISK(lsn) (((__be32 *)&(lsn))[0]) static inline xfs_lsn_t xlog_assign_lsn(uint cycle, uint block) { return ((xfs_lsn_t)cycle << 32) | block; } static inline uint xlog_get_cycle(char *ptr) { if (be32_to_cpu(*(__be32 *)ptr) == XLOG_HEADER_MAGIC_NUM) return be32_to_cpu(*((__be32 *)ptr + 1)); else return be32_to_cpu(*(__be32 *)ptr); } /* Log Clients */ #define XFS_TRANSACTION 0x69 #define XFS_VOLUME 0x2 #define XFS_LOG 0xaa #define XLOG_UNMOUNT_TYPE 0x556e /* Un for Unmount */ /* Region types for iovec's i_type */ #define XLOG_REG_TYPE_BFORMAT 1 #define XLOG_REG_TYPE_BCHUNK 2 #define XLOG_REG_TYPE_EFI_FORMAT 3 #define XLOG_REG_TYPE_EFD_FORMAT 4 #define XLOG_REG_TYPE_IFORMAT 5 #define XLOG_REG_TYPE_ICORE 6 #define XLOG_REG_TYPE_IEXT 7 #define XLOG_REG_TYPE_IBROOT 8 #define XLOG_REG_TYPE_ILOCAL 9 #define XLOG_REG_TYPE_IATTR_EXT 10 #define XLOG_REG_TYPE_IATTR_BROOT 11 #define XLOG_REG_TYPE_IATTR_LOCAL 12 #define XLOG_REG_TYPE_QFORMAT 13 #define XLOG_REG_TYPE_DQUOT 14 #define XLOG_REG_TYPE_QUOTAOFF 15 #define XLOG_REG_TYPE_LRHEADER 16 #define XLOG_REG_TYPE_UNMOUNT 17 #define XLOG_REG_TYPE_COMMIT 18 #define XLOG_REG_TYPE_TRANSHDR 19 #define XLOG_REG_TYPE_ICREATE 20 #define XLOG_REG_TYPE_MAX 20 /* * Flags to log operation header * * The first write of a new transaction will be preceded with a start * record, XLOG_START_TRANS. Once a transaction is committed, a commit * record is written, XLOG_COMMIT_TRANS. If a single region can not fit into * the remainder of the current active in-core log, it is split up into * multiple regions. Each partial region will be marked with a * XLOG_CONTINUE_TRANS until the last one, which gets marked with XLOG_END_TRANS. * */ #define XLOG_START_TRANS 0x01 /* Start a new transaction */ #define XLOG_COMMIT_TRANS 0x02 /* Commit this transaction */ #define XLOG_CONTINUE_TRANS 0x04 /* Cont this trans into new region */ #define XLOG_WAS_CONT_TRANS 0x08 /* Cont this trans into new region */ #define XLOG_END_TRANS 0x10 /* End a continued transaction */ #define XLOG_UNMOUNT_TRANS 0x20 /* Unmount a filesystem transaction */ typedef struct xlog_op_header { __be32 oh_tid; /* transaction id of operation : 4 b */ __be32 oh_len; /* bytes in data region : 4 b */ __u8 oh_clientid; /* who sent me this : 1 b */ __u8 oh_flags; /* : 1 b */ __u16 oh_res2; /* 32 bit align : 2 b */ } xlog_op_header_t; /* valid values for h_fmt */ #define XLOG_FMT_UNKNOWN 0 #define XLOG_FMT_LINUX_LE 1 #define XLOG_FMT_LINUX_BE 2 #define XLOG_FMT_IRIX_BE 3 /* our fmt */ #ifdef XFS_NATIVE_HOST #define XLOG_FMT XLOG_FMT_LINUX_BE #else #define XLOG_FMT XLOG_FMT_LINUX_LE #endif typedef struct xlog_rec_header { __be32 h_magicno; /* log record (LR) identifier : 4 */ __be32 h_cycle; /* write cycle of log : 4 */ __be32 h_version; /* LR version : 4 */ __be32 h_len; /* len in bytes; should be 64-bit aligned: 4 */ __be64 h_lsn; /* lsn of this LR : 8 */ __be64 h_tail_lsn; /* lsn of 1st LR w/ buffers not committed: 8 */ __le32 h_crc; /* crc of log record : 4 */ __be32 h_prev_block; /* block number to previous LR : 4 */ __be32 h_num_logops; /* number of log operations in this LR : 4 */ __be32 h_cycle_data[XLOG_HEADER_CYCLE_SIZE / BBSIZE]; /* new fields */ __be32 h_fmt; /* format of log record : 4 */ uuid_t h_fs_uuid; /* uuid of FS : 16 */ __be32 h_size; /* iclog size : 4 */ } xlog_rec_header_t; typedef struct xlog_rec_ext_header { __be32 xh_cycle; /* write cycle of log : 4 */ __be32 xh_cycle_data[XLOG_HEADER_CYCLE_SIZE / BBSIZE]; /* : 256 */ } xlog_rec_ext_header_t; /* * Quite misnamed, because this union lays out the actual on-disk log buffer. */ typedef union xlog_in_core2 { xlog_rec_header_t hic_header; xlog_rec_ext_header_t hic_xheader; char hic_sector[XLOG_HEADER_SIZE]; } xlog_in_core_2_t; /* not an on-disk structure, but needed by log recovery in userspace */ typedef struct xfs_log_iovec { void *i_addr; /* beginning address of region */ int i_len; /* length in bytes of region */ uint i_type; /* type of region */ } xfs_log_iovec_t; /* * Transaction Header definitions. * * This is the structure written in the log at the head of every transaction. It * identifies the type and id of the transaction, and contains the number of * items logged by the transaction so we know how many to expect during * recovery. * * Do not change the below structure without redoing the code in * xlog_recover_add_to_trans() and xlog_recover_add_to_cont_trans(). */ typedef struct xfs_trans_header { uint th_magic; /* magic number */ uint th_type; /* transaction type */ __int32_t th_tid; /* transaction id (unused) */ uint th_num_items; /* num items logged by trans */ } xfs_trans_header_t; #define XFS_TRANS_HEADER_MAGIC 0x5452414e /* TRAN */ /* * Log item types. */ #define XFS_LI_EFI 0x1236 #define XFS_LI_EFD 0x1237 #define XFS_LI_IUNLINK 0x1238 #define XFS_LI_INODE 0x123b /* aligned ino chunks, var-size ibufs */ #define XFS_LI_BUF 0x123c /* v2 bufs, variable sized inode bufs */ #define XFS_LI_DQUOT 0x123d #define XFS_LI_QUOTAOFF 0x123e #define XFS_LI_ICREATE 0x123f #define XFS_LI_TYPE_DESC \ { XFS_LI_EFI, "XFS_LI_EFI" }, \ { XFS_LI_EFD, "XFS_LI_EFD" }, \ { XFS_LI_IUNLINK, "XFS_LI_IUNLINK" }, \ { XFS_LI_INODE, "XFS_LI_INODE" }, \ { XFS_LI_BUF, "XFS_LI_BUF" }, \ { XFS_LI_DQUOT, "XFS_LI_DQUOT" }, \ { XFS_LI_QUOTAOFF, "XFS_LI_QUOTAOFF" }, \ { XFS_LI_ICREATE, "XFS_LI_ICREATE" } /* * Inode Log Item Format definitions. * * This is the structure used to lay out an inode log item in the * log. The size of the inline data/extents/b-tree root to be logged * (if any) is indicated in the ilf_dsize field. Changes to this structure * must be added on to the end. */ typedef struct xfs_inode_log_format { __uint16_t ilf_type; /* inode log item type */ __uint16_t ilf_size; /* size of this item */ __uint32_t ilf_fields; /* flags for fields logged */ __uint16_t ilf_asize; /* size of attr d/ext/root */ __uint16_t ilf_dsize; /* size of data/ext/root */ __uint64_t ilf_ino; /* inode number */ union { __uint32_t ilfu_rdev; /* rdev value for dev inode*/ uuid_t ilfu_uuid; /* mount point value */ } ilf_u; __int64_t ilf_blkno; /* blkno of inode buffer */ __int32_t ilf_len; /* len of inode buffer */ __int32_t ilf_boffset; /* off of inode in buffer */ } xfs_inode_log_format_t; typedef struct xfs_inode_log_format_32 { __uint16_t ilf_type; /* inode log item type */ __uint16_t ilf_size; /* size of this item */ __uint32_t ilf_fields; /* flags for fields logged */ __uint16_t ilf_asize; /* size of attr d/ext/root */ __uint16_t ilf_dsize; /* size of data/ext/root */ __uint64_t ilf_ino; /* inode number */ union { __uint32_t ilfu_rdev; /* rdev value for dev inode*/ uuid_t ilfu_uuid; /* mount point value */ } ilf_u; __int64_t ilf_blkno; /* blkno of inode buffer */ __int32_t ilf_len; /* len of inode buffer */ __int32_t ilf_boffset; /* off of inode in buffer */ } __attribute__((packed)) xfs_inode_log_format_32_t; typedef struct xfs_inode_log_format_64 { __uint16_t ilf_type; /* inode log item type */ __uint16_t ilf_size; /* size of this item */ __uint32_t ilf_fields; /* flags for fields logged */ __uint16_t ilf_asize; /* size of attr d/ext/root */ __uint16_t ilf_dsize; /* size of data/ext/root */ __uint32_t ilf_pad; /* pad for 64 bit boundary */ __uint64_t ilf_ino; /* inode number */ union { __uint32_t ilfu_rdev; /* rdev value for dev inode*/ uuid_t ilfu_uuid; /* mount point value */ } ilf_u; __int64_t ilf_blkno; /* blkno of inode buffer */ __int32_t ilf_len; /* len of inode buffer */ __int32_t ilf_boffset; /* off of inode in buffer */ } xfs_inode_log_format_64_t; /* * Flags for xfs_trans_log_inode flags field. */ #define XFS_ILOG_CORE 0x001 /* log standard inode fields */ #define XFS_ILOG_DDATA 0x002 /* log i_df.if_data */ #define XFS_ILOG_DEXT 0x004 /* log i_df.if_extents */ #define XFS_ILOG_DBROOT 0x008 /* log i_df.i_broot */ #define XFS_ILOG_DEV 0x010 /* log the dev field */ #define XFS_ILOG_UUID 0x020 /* log the uuid field */ #define XFS_ILOG_ADATA 0x040 /* log i_af.if_data */ #define XFS_ILOG_AEXT 0x080 /* log i_af.if_extents */ #define XFS_ILOG_ABROOT 0x100 /* log i_af.i_broot */ #define XFS_ILOG_DOWNER 0x200 /* change the data fork owner on replay */ #define XFS_ILOG_AOWNER 0x400 /* change the attr fork owner on replay */ /* * The timestamps are dirty, but not necessarily anything else in the inode * core. Unlike the other fields above this one must never make it to disk * in the ilf_fields of the inode_log_format, but is purely store in-memory in * ili_fields in the inode_log_item. */ #define XFS_ILOG_TIMESTAMP 0x4000 #define XFS_ILOG_NONCORE (XFS_ILOG_DDATA | XFS_ILOG_DEXT | \ XFS_ILOG_DBROOT | XFS_ILOG_DEV | \ XFS_ILOG_UUID | XFS_ILOG_ADATA | \ XFS_ILOG_AEXT | XFS_ILOG_ABROOT | \ XFS_ILOG_DOWNER | XFS_ILOG_AOWNER) #define XFS_ILOG_DFORK (XFS_ILOG_DDATA | XFS_ILOG_DEXT | \ XFS_ILOG_DBROOT) #define XFS_ILOG_AFORK (XFS_ILOG_ADATA | XFS_ILOG_AEXT | \ XFS_ILOG_ABROOT) #define XFS_ILOG_ALL (XFS_ILOG_CORE | XFS_ILOG_DDATA | \ XFS_ILOG_DEXT | XFS_ILOG_DBROOT | \ XFS_ILOG_DEV | XFS_ILOG_UUID | \ XFS_ILOG_ADATA | XFS_ILOG_AEXT | \ XFS_ILOG_ABROOT | XFS_ILOG_TIMESTAMP | \ XFS_ILOG_DOWNER | XFS_ILOG_AOWNER) static inline int xfs_ilog_fbroot(int w) { return (w == XFS_DATA_FORK ? XFS_ILOG_DBROOT : XFS_ILOG_ABROOT); } static inline int xfs_ilog_fext(int w) { return (w == XFS_DATA_FORK ? XFS_ILOG_DEXT : XFS_ILOG_AEXT); } static inline int xfs_ilog_fdata(int w) { return (w == XFS_DATA_FORK ? XFS_ILOG_DDATA : XFS_ILOG_ADATA); } /* * Incore version of the on-disk inode core structures. We log this directly * into the journal in host CPU format (for better or worse) and as such * directly mirrors the xfs_dinode structure as it must contain all the same * information. */ typedef struct xfs_ictimestamp { __int32_t t_sec; /* timestamp seconds */ __int32_t t_nsec; /* timestamp nanoseconds */ } xfs_ictimestamp_t; /* * NOTE: This structure must be kept identical to struct xfs_dinode * except for the endianness annotations. */ typedef struct xfs_icdinode { __uint16_t di_magic; /* inode magic # = XFS_DINODE_MAGIC */ __uint16_t di_mode; /* mode and type of file */ __int8_t di_version; /* inode version */ __int8_t di_format; /* format of di_c data */ __uint16_t di_onlink; /* old number of links to file */ __uint32_t di_uid; /* owner's user id */ __uint32_t di_gid; /* owner's group id */ __uint32_t di_nlink; /* number of links to file */ __uint16_t di_projid_lo; /* lower part of owner's project id */ __uint16_t di_projid_hi; /* higher part of owner's project id */ __uint8_t di_pad[6]; /* unused, zeroed space */ __uint16_t di_flushiter; /* incremented on flush */ xfs_ictimestamp_t di_atime; /* time last accessed */ xfs_ictimestamp_t di_mtime; /* time last modified */ xfs_ictimestamp_t di_ctime; /* time created/inode modified */ xfs_fsize_t di_size; /* number of bytes in file */ xfs_rfsblock_t di_nblocks; /* # of direct & btree blocks used */ xfs_extlen_t di_extsize; /* basic/minimum extent size for file */ xfs_extnum_t di_nextents; /* number of extents in data fork */ xfs_aextnum_t di_anextents; /* number of extents in attribute fork*/ __uint8_t di_forkoff; /* attr fork offs, <<3 for 64b align */ __int8_t di_aformat; /* format of attr fork's data */ __uint32_t di_dmevmask; /* DMIG event mask */ __uint16_t di_dmstate; /* DMIG state info */ __uint16_t di_flags; /* random flags, XFS_DIFLAG_... */ __uint32_t di_gen; /* generation number */ /* di_next_unlinked is the only non-core field in the old dinode */ xfs_agino_t di_next_unlinked;/* agi unlinked list ptr */ /* start of the extended dinode, writable fields */ __uint32_t di_crc; /* CRC of the inode */ __uint64_t di_changecount; /* number of attribute changes */ xfs_lsn_t di_lsn; /* flush sequence */ __uint64_t di_flags2; /* more random flags */ __uint8_t di_pad2[16]; /* more padding for future expansion */ /* fields only written to during inode creation */ xfs_ictimestamp_t di_crtime; /* time created */ xfs_ino_t di_ino; /* inode number */ uuid_t di_uuid; /* UUID of the filesystem */ /* structure must be padded to 64 bit alignment */ } xfs_icdinode_t; static inline uint xfs_icdinode_size(int version) { if (version == 3) return sizeof(struct xfs_icdinode); return offsetof(struct xfs_icdinode, di_next_unlinked); } /* * Buffer Log Format defintions * * These are the physical dirty bitmap defintions for the log format structure. */ #define XFS_BLF_CHUNK 128 #define XFS_BLF_SHIFT 7 #define BIT_TO_WORD_SHIFT 5 #define NBWORD (NBBY * sizeof(unsigned int)) /* * This flag indicates that the buffer contains on disk inodes * and requires special recovery handling. */ #define XFS_BLF_INODE_BUF (1<<0) /* * This flag indicates that the buffer should not be replayed * during recovery because its blocks are being freed. */ #define XFS_BLF_CANCEL (1<<1) /* * This flag indicates that the buffer contains on disk * user or group dquots and may require special recovery handling. */ #define XFS_BLF_UDQUOT_BUF (1<<2) #define XFS_BLF_PDQUOT_BUF (1<<3) #define XFS_BLF_GDQUOT_BUF (1<<4) /* * This is the structure used to lay out a buf log item in the * log. The data map describes which 128 byte chunks of the buffer * have been logged. */ #define XFS_BLF_DATAMAP_SIZE ((XFS_MAX_BLOCKSIZE / XFS_BLF_CHUNK) / NBWORD) typedef struct xfs_buf_log_format { unsigned short blf_type; /* buf log item type indicator */ unsigned short blf_size; /* size of this item */ unsigned short blf_flags; /* misc state */ unsigned short blf_len; /* number of blocks in this buf */ __int64_t blf_blkno; /* starting blkno of this buf */ unsigned int blf_map_size; /* used size of data bitmap in words */ unsigned int blf_data_map[XFS_BLF_DATAMAP_SIZE]; /* dirty bitmap */ } xfs_buf_log_format_t; /* * All buffers now need to tell recovery where the magic number * is so that it can verify and calculate the CRCs on the buffer correctly * once the changes have been replayed into the buffer. * * The type value is held in the upper 5 bits of the blf_flags field, which is * an unsigned 16 bit field. Hence we need to shift it 11 bits up and down. */ #define XFS_BLFT_BITS 5 #define XFS_BLFT_SHIFT 11 #define XFS_BLFT_MASK (((1 << XFS_BLFT_BITS) - 1) << XFS_BLFT_SHIFT) enum xfs_blft { XFS_BLFT_UNKNOWN_BUF = 0, XFS_BLFT_UDQUOT_BUF, XFS_BLFT_PDQUOT_BUF, XFS_BLFT_GDQUOT_BUF, XFS_BLFT_BTREE_BUF, XFS_BLFT_AGF_BUF, XFS_BLFT_AGFL_BUF, XFS_BLFT_AGI_BUF, XFS_BLFT_DINO_BUF, XFS_BLFT_SYMLINK_BUF, XFS_BLFT_DIR_BLOCK_BUF, XFS_BLFT_DIR_DATA_BUF, XFS_BLFT_DIR_FREE_BUF, XFS_BLFT_DIR_LEAF1_BUF, XFS_BLFT_DIR_LEAFN_BUF, XFS_BLFT_DA_NODE_BUF, XFS_BLFT_ATTR_LEAF_BUF, XFS_BLFT_ATTR_RMT_BUF, XFS_BLFT_SB_BUF, XFS_BLFT_MAX_BUF = (1 << XFS_BLFT_BITS), }; static inline void xfs_blft_to_flags(struct xfs_buf_log_format *blf, enum xfs_blft type) { ASSERT(type > XFS_BLFT_UNKNOWN_BUF && type < XFS_BLFT_MAX_BUF); blf->blf_flags &= ~XFS_BLFT_MASK; blf->blf_flags |= ((type << XFS_BLFT_SHIFT) & XFS_BLFT_MASK); } static inline __uint16_t xfs_blft_from_flags(struct xfs_buf_log_format *blf) { return (blf->blf_flags & XFS_BLFT_MASK) >> XFS_BLFT_SHIFT; } /* * EFI/EFD log format definitions */ typedef struct xfs_extent { xfs_fsblock_t ext_start; xfs_extlen_t ext_len; } xfs_extent_t; /* * Since an xfs_extent_t has types (start:64, len: 32) * there are different alignments on 32 bit and 64 bit kernels. * So we provide the different variants for use by a * conversion routine. */ typedef struct xfs_extent_32 { __uint64_t ext_start; __uint32_t ext_len; } __attribute__((packed)) xfs_extent_32_t; typedef struct xfs_extent_64 { __uint64_t ext_start; __uint32_t ext_len; __uint32_t ext_pad; } xfs_extent_64_t; /* * This is the structure used to lay out an efi log item in the * log. The efi_extents field is a variable size array whose * size is given by efi_nextents. */ typedef struct xfs_efi_log_format { __uint16_t efi_type; /* efi log item type */ __uint16_t efi_size; /* size of this item */ __uint32_t efi_nextents; /* # extents to free */ __uint64_t efi_id; /* efi identifier */ xfs_extent_t efi_extents[1]; /* array of extents to free */ } xfs_efi_log_format_t; typedef struct xfs_efi_log_format_32 { __uint16_t efi_type; /* efi log item type */ __uint16_t efi_size; /* size of this item */ __uint32_t efi_nextents; /* # extents to free */ __uint64_t efi_id; /* efi identifier */ xfs_extent_32_t efi_extents[1]; /* array of extents to free */ } __attribute__((packed)) xfs_efi_log_format_32_t; typedef struct xfs_efi_log_format_64 { __uint16_t efi_type; /* efi log item type */ __uint16_t efi_size; /* size of this item */ __uint32_t efi_nextents; /* # extents to free */ __uint64_t efi_id; /* efi identifier */ xfs_extent_64_t efi_extents[1]; /* array of extents to free */ } xfs_efi_log_format_64_t; /* * This is the structure used to lay out an efd log item in the * log. The efd_extents array is a variable size array whose * size is given by efd_nextents; */ typedef struct xfs_efd_log_format { __uint16_t efd_type; /* efd log item type */ __uint16_t efd_size; /* size of this item */ __uint32_t efd_nextents; /* # of extents freed */ __uint64_t efd_efi_id; /* id of corresponding efi */ xfs_extent_t efd_extents[1]; /* array of extents freed */ } xfs_efd_log_format_t; typedef struct xfs_efd_log_format_32 { __uint16_t efd_type; /* efd log item type */ __uint16_t efd_size; /* size of this item */ __uint32_t efd_nextents; /* # of extents freed */ __uint64_t efd_efi_id; /* id of corresponding efi */ xfs_extent_32_t efd_extents[1]; /* array of extents freed */ } __attribute__((packed)) xfs_efd_log_format_32_t; typedef struct xfs_efd_log_format_64 { __uint16_t efd_type; /* efd log item type */ __uint16_t efd_size; /* size of this item */ __uint32_t efd_nextents; /* # of extents freed */ __uint64_t efd_efi_id; /* id of corresponding efi */ xfs_extent_64_t efd_extents[1]; /* array of extents freed */ } xfs_efd_log_format_64_t; /* * Dquot Log format definitions. * * The first two fields must be the type and size fitting into * 32 bits : log_recovery code assumes that. */ typedef struct xfs_dq_logformat { __uint16_t qlf_type; /* dquot log item type */ __uint16_t qlf_size; /* size of this item */ xfs_dqid_t qlf_id; /* usr/grp/proj id : 32 bits */ __int64_t qlf_blkno; /* blkno of dquot buffer */ __int32_t qlf_len; /* len of dquot buffer */ __uint32_t qlf_boffset; /* off of dquot in buffer */ } xfs_dq_logformat_t; /* * log format struct for QUOTAOFF records. * The first two fields must be the type and size fitting into * 32 bits : log_recovery code assumes that. * We write two LI_QUOTAOFF logitems per quotaoff, the last one keeps a pointer * to the first and ensures that the first logitem is taken out of the AIL * only when the last one is securely committed. */ typedef struct xfs_qoff_logformat { unsigned short qf_type; /* quotaoff log item type */ unsigned short qf_size; /* size of this item */ unsigned int qf_flags; /* USR and/or GRP */ char qf_pad[12]; /* padding for future */ } xfs_qoff_logformat_t; /* * Disk quotas status in m_qflags, and also sb_qflags. 16 bits. */ #define XFS_UQUOTA_ACCT 0x0001 /* user quota accounting ON */ #define XFS_UQUOTA_ENFD 0x0002 /* user quota limits enforced */ #define XFS_UQUOTA_CHKD 0x0004 /* quotacheck run on usr quotas */ #define XFS_PQUOTA_ACCT 0x0008 /* project quota accounting ON */ #define XFS_OQUOTA_ENFD 0x0010 /* other (grp/prj) quota limits enforced */ #define XFS_OQUOTA_CHKD 0x0020 /* quotacheck run on other (grp/prj) quotas */ #define XFS_GQUOTA_ACCT 0x0040 /* group quota accounting ON */ /* * Conversion to and from the combined OQUOTA flag (if necessary) * is done only in xfs_sb_qflags_to_disk() and xfs_sb_qflags_from_disk() */ #define XFS_GQUOTA_ENFD 0x0080 /* group quota limits enforced */ #define XFS_GQUOTA_CHKD 0x0100 /* quotacheck run on group quotas */ #define XFS_PQUOTA_ENFD 0x0200 /* project quota limits enforced */ #define XFS_PQUOTA_CHKD 0x0400 /* quotacheck run on project quotas */ #define XFS_ALL_QUOTA_ACCT \ (XFS_UQUOTA_ACCT | XFS_GQUOTA_ACCT | XFS_PQUOTA_ACCT) #define XFS_ALL_QUOTA_ENFD \ (XFS_UQUOTA_ENFD | XFS_GQUOTA_ENFD | XFS_PQUOTA_ENFD) #define XFS_ALL_QUOTA_CHKD \ (XFS_UQUOTA_CHKD | XFS_GQUOTA_CHKD | XFS_PQUOTA_CHKD) #define XFS_MOUNT_QUOTA_ALL (XFS_UQUOTA_ACCT|XFS_UQUOTA_ENFD|\ XFS_UQUOTA_CHKD|XFS_GQUOTA_ACCT|\ XFS_GQUOTA_ENFD|XFS_GQUOTA_CHKD|\ XFS_PQUOTA_ACCT|XFS_PQUOTA_ENFD|\ XFS_PQUOTA_CHKD) /* * Inode create log item structure * * Log recovery assumes the first two entries are the type and size and they fit * in 32 bits. Also in host order (ugh) so they have to be 32 bit aligned so * decoding can be done correctly. */ struct xfs_icreate_log { __uint16_t icl_type; /* type of log format structure */ __uint16_t icl_size; /* size of log format structure */ __be32 icl_ag; /* ag being allocated in */ __be32 icl_agbno; /* start block of inode range */ __be32 icl_count; /* number of inodes to initialise */ __be32 icl_isize; /* size of inodes */ __be32 icl_length; /* length of extent to initialise */ __be32 icl_gen; /* inode generation number to use */ }; #endif /* __XFS_LOG_FORMAT_H__ */ partclone-0.2.86/src/xfs/xfs_log_recover.h000066400000000000000000000037361262102574200205360ustar00rootroot00000000000000/* * Copyright (c) 2000,2005 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __XFS_LOG_RECOVER_H__ #define __XFS_LOG_RECOVER_H__ /* * Macros, structures, prototypes for internal log manager use. */ #define XLOG_RHASH_BITS 4 #define XLOG_RHASH_SIZE 16 #define XLOG_RHASH_SHIFT 2 #define XLOG_RHASH(tid) \ ((((__uint32_t)tid)>>XLOG_RHASH_SHIFT) & (XLOG_RHASH_SIZE-1)) #define XLOG_MAX_REGIONS_IN_ITEM (XFS_MAX_BLOCKSIZE / XFS_BLF_CHUNK / 2 + 1) /* * item headers are in ri_buf[0]. Additional buffers follow. */ typedef struct xlog_recover_item { struct list_head ri_list; int ri_type; int ri_cnt; /* count of regions found */ int ri_total; /* total regions */ xfs_log_iovec_t *ri_buf; /* ptr to regions buffer */ } xlog_recover_item_t; struct xlog_tid; typedef struct xlog_recover { struct hlist_node r_list; xlog_tid_t r_log_tid; /* log's transaction id */ xfs_trans_header_t r_theader; /* trans header for partial */ int r_state; /* not needed */ xfs_lsn_t r_lsn; /* xact lsn */ struct list_head r_itemq; /* q for items */ } xlog_recover_t; #define ITEM_TYPE(i) (*(unsigned short *)(i)->ri_buf[0].i_addr) /* * This is the number of entries in the l_buf_cancel_table used during * recovery. */ #define XLOG_BC_TABLE_SIZE 64 #define XLOG_RECOVER_PASS1 1 #define XLOG_RECOVER_PASS2 2 #endif /* __XFS_LOG_RECOVER_H__ */ partclone-0.2.86/src/xfs/xfs_log_rlimit.c000066400000000000000000000112721262102574200203560ustar00rootroot00000000000000/* * Copyright (c) 2013 Jie Liu. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_mount.h" #include "xfs_da_format.h" #include "xfs_trans_space.h" #include "xfs_inode.h" #include "xfs_da_btree.h" #include "xfs_attr_leaf.h" #include "xfs_bmap_btree.h" /* * Calculate the maximum length in bytes that would be required for a local * attribute value as large attributes out of line are not logged. */ STATIC int xfs_log_calc_max_attrsetm_res( struct xfs_mount *mp) { int size; int nblks; size = xfs_attr_leaf_entsize_local_max(mp->m_attr_geo->blksize) - MAXNAMELEN - 1; nblks = XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK); nblks += XFS_B_TO_FSB(mp, size); nblks += XFS_NEXTENTADD_SPACE_RES(mp, size, XFS_ATTR_FORK); return M_RES(mp)->tr_attrsetm.tr_logres + M_RES(mp)->tr_attrsetrt.tr_logres * nblks; } /* * Iterate over the log space reservation table to figure out and return * the maximum one in terms of the pre-calculated values which were done * at mount time. */ STATIC void xfs_log_get_max_trans_res( struct xfs_mount *mp, struct xfs_trans_res *max_resp) { struct xfs_trans_res *resp; struct xfs_trans_res *end_resp; int log_space = 0; int attr_space; attr_space = xfs_log_calc_max_attrsetm_res(mp); resp = (struct xfs_trans_res *)M_RES(mp); end_resp = (struct xfs_trans_res *)(M_RES(mp) + 1); for (; resp < end_resp; resp++) { int tmp = resp->tr_logcount > 1 ? resp->tr_logres * resp->tr_logcount : resp->tr_logres; if (log_space < tmp) { log_space = tmp; *max_resp = *resp; /* struct copy */ } } if (attr_space > log_space) { *max_resp = M_RES(mp)->tr_attrsetm; /* struct copy */ max_resp->tr_logres = attr_space; } } /* * Calculate the minimum valid log size for the given superblock configuration. * Used to calculate the minimum log size at mkfs time, and to determine if * the log is large enough or not at mount time. Returns the minimum size in * filesystem block size units. */ int xfs_log_calc_minimum_size( struct xfs_mount *mp) { struct xfs_trans_res tres = {0}; int max_logres; int min_logblks = 0; int lsunit = 0; xfs_log_get_max_trans_res(mp, &tres); max_logres = xfs_log_calc_unit_res(mp, tres.tr_logres); if (tres.tr_logcount > 1) max_logres *= tres.tr_logcount; if (xfs_sb_version_haslogv2(&mp->m_sb) && mp->m_sb.sb_logsunit > 1) lsunit = BTOBB(mp->m_sb.sb_logsunit); /* * Two factors should be taken into account for calculating the minimum * log space. * 1) The fundamental limitation is that no single transaction can be * larger than half size of the log. * * From mkfs.xfs, this is considered by the XFS_MIN_LOG_FACTOR * define, which is set to 3. That means we can definitely fit * maximally sized 2 transactions in the log. We'll use this same * value here. * * 2) If the lsunit option is specified, a transaction requires 2 LSU * for the reservation because there are two log writes that can * require padding - the transaction data and the commit record which * are written separately and both can require padding to the LSU. * Consider that we can have an active CIL reservation holding 2*LSU, * but the CIL is not over a push threshold, in this case, if we * don't have enough log space for at one new transaction, which * includes another 2*LSU in the reservation, we will run into dead * loop situation in log space grant procedure. i.e. * xlog_grant_head_wait(). * * Hence the log size needs to be able to contain two maximally sized * and padded transactions, which is (2 * (2 * LSU + maxlres)). * * Also, the log size should be a multiple of the log stripe unit, round * it up to lsunit boundary if lsunit is specified. */ if (lsunit) { min_logblks = roundup_64(BTOBB(max_logres), lsunit) + 2 * lsunit; } else min_logblks = BTOBB(max_logres) + 2 * BBSIZE; min_logblks *= XFS_MIN_LOG_FACTOR; return XFS_BB_TO_FSB(mp, min_logblks); } partclone-0.2.86/src/xfs/xfs_metadump.h000066400000000000000000000020021262102574200200250ustar00rootroot00000000000000/* * Copyright (c) 2007 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _XFS_METADUMP_H_ #define _XFS_METADUMP_H_ #define XFS_MD_MAGIC 0x5846534d /* 'XFSM' */ typedef struct xfs_metablock { __be32 mb_magic; __be16 mb_count; __uint8_t mb_blocklog; __uint8_t mb_reserved; /* followed by an array of xfs_daddr_t */ } xfs_metablock_t; #endif /* _XFS_METADUMP_H_ */ partclone-0.2.86/src/xfs/xfs_mount.h000066400000000000000000000133101262102574200173570ustar00rootroot00000000000000/* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __XFS_MOUNT_H__ #define __XFS_MOUNT_H__ struct xfs_inode; struct xfs_buftarg; struct xfs_dir_ops; struct xfs_da_geometry; /* * Define a user-level mount structure with all we need * in order to make use of the numerous XFS_* macros. */ typedef struct xfs_mount { xfs_sb_t m_sb; /* copy of fs superblock */ #define m_icount m_sb.sb_icount #define m_ifree m_sb.sb_ifree #define m_fdblocks m_sb.sb_fdblocks char *m_fsname; /* filesystem name */ int m_bsize; /* fs logical block size */ xfs_agnumber_t m_agfrotor; /* last ag where space found */ xfs_agnumber_t m_agirotor; /* last ag dir inode alloced */ xfs_agnumber_t m_maxagi; /* highest inode alloc group */ uint m_rsumlevels; /* rt summary levels */ uint m_rsumsize; /* size of rt summary, bytes */ struct xfs_inode *m_rbmip; /* pointer to bitmap inode */ struct xfs_inode *m_rsumip; /* pointer to summary inode */ struct xfs_buftarg *m_ddev_targp; struct xfs_buftarg *m_logdev_targp; struct xfs_buftarg *m_rtdev_targp; #define m_dev m_ddev_targp #define m_logdev m_logdev_targp #define m_rtdev m_rtdev_targp __uint8_t m_dircook_elog; /* log d-cookie entry bits */ __uint8_t m_blkbit_log; /* blocklog + NBBY */ __uint8_t m_blkbb_log; /* blocklog - BBSHIFT */ __uint8_t m_sectbb_log; /* sectorlog - BBSHIFT */ __uint8_t m_agno_log; /* log #ag's */ __uint8_t m_agino_log; /* #bits for agino in inum */ uint m_inode_cluster_size;/* min inode buf size */ uint m_blockmask; /* sb_blocksize-1 */ uint m_blockwsize; /* sb_blocksize in words */ uint m_blockwmask; /* blockwsize-1 */ uint m_alloc_mxr[2]; /* XFS_ALLOC_BLOCK_MAXRECS */ uint m_alloc_mnr[2]; /* XFS_ALLOC_BLOCK_MINRECS */ uint m_bmap_dmxr[2]; /* XFS_BMAP_BLOCK_DMAXRECS */ uint m_bmap_dmnr[2]; /* XFS_BMAP_BLOCK_DMINRECS */ uint m_inobt_mxr[2]; /* XFS_INOBT_BLOCK_MAXRECS */ uint m_inobt_mnr[2]; /* XFS_INOBT_BLOCK_MINRECS */ uint m_ag_maxlevels; /* XFS_AG_MAXLEVELS */ uint m_bm_maxlevels[2]; /* XFS_BM_MAXLEVELS */ uint m_in_maxlevels; /* XFS_IN_MAXLEVELS */ struct radix_tree_root m_perag_tree; uint m_flags; /* global mount flags */ uint m_qflags; /* quota status flags */ uint m_attroffset; /* inode attribute offset */ int m_ialloc_inos; /* inodes in inode allocation */ int m_ialloc_blks; /* blocks in inode allocation */ int m_ialloc_min_blks; /* min blocks in sparse inode * allocation */ int m_litino; /* size of inode union area */ int m_inoalign_mask;/* mask sb_inoalignmt if used */ struct xfs_trans_resv m_resv; /* precomputed res values */ __uint64_t m_maxicount; /* maximum inode count */ int m_dalign; /* stripe unit */ int m_swidth; /* stripe width */ int m_sinoalign; /* stripe unit inode alignmnt */ const struct xfs_nameops *m_dirnameops; /* vector of dir name ops */ struct xfs_da_geometry *m_dir_geo; /* directory block geometry */ struct xfs_da_geometry *m_attr_geo; /* attribute block geometry */ const struct xfs_dir_ops *m_dir_inode_ops; /* vector of dir inode ops */ const struct xfs_dir_ops *m_nondir_inode_ops; /* !dir inode ops */ #define M_DIROPS(mp) ((mp)->m_dir_inode_ops) /* * anonymous struct to allow xfs_dquot_buf.c to compile. * Pointer is always null in userspace, so code does not use it at all */ struct { int qi_dqperchunk; } *m_quotainfo; } xfs_mount_t; /* * Per-ag incore structure, copies of information in agf and agi, * to improve the performance of allocation group selection. */ typedef struct xfs_perag { struct xfs_mount *pag_mount; /* owner filesystem */ xfs_agnumber_t pag_agno; /* AG this structure belongs to */ atomic_t pag_ref; /* perag reference count */ char pagf_init; /* this agf's entry is initialized */ char pagi_init; /* this agi's entry is initialized */ char pagf_metadata; /* the agf is preferred to be metadata */ char pagi_inodeok; /* The agi is ok for inodes */ __uint8_t pagf_levels[XFS_BTNUM_AGF]; /* # of levels in bno & cnt btree */ __uint32_t pagf_flcount; /* count of blocks in freelist */ xfs_extlen_t pagf_freeblks; /* total free blocks */ xfs_extlen_t pagf_longest; /* longest free space */ __uint32_t pagf_btreeblks; /* # of blocks held in AGF btrees */ xfs_agino_t pagi_freecount; /* number of free inodes */ xfs_agino_t pagi_count; /* number of allocated inodes */ /* * Inode allocation search lookup optimisation. * If the pagino matches, the search for new inodes * doesn't need to search the near ones again straight away */ xfs_agino_t pagl_pagino; xfs_agino_t pagl_leftrec; xfs_agino_t pagl_rightrec; int pagb_count; /* pagb slots in use */ } xfs_perag_t; #define LIBXFS_MOUNT_DEBUGGER 0x0001 #define LIBXFS_MOUNT_32BITINODES 0x0002 #define LIBXFS_MOUNT_32BITINOOPT 0x0004 #define LIBXFS_MOUNT_COMPAT_ATTR 0x0008 #define LIBXFS_MOUNT_ATTR2 0x0010 #define LIBXFS_BHASHSIZE(sbp) (1<<10) extern xfs_mount_t *libxfs_mount (xfs_mount_t *, xfs_sb_t *, dev_t, dev_t, dev_t, int); extern void libxfs_umount (xfs_mount_t *); extern void libxfs_rtmount_destroy (xfs_mount_t *); #endif /* __XFS_MOUNT_H__ */ partclone-0.2.86/src/xfs/xfs_quota_defs.h000066400000000000000000000145701262102574200203600ustar00rootroot00000000000000/* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __XFS_QUOTA_DEFS_H__ #define __XFS_QUOTA_DEFS_H__ /* * Quota definitions shared between user and kernel source trees. */ /* * Even though users may not have quota limits occupying all 64-bits, * they may need 64-bit accounting. Hence, 64-bit quota-counters, * and quota-limits. This is a waste in the common case, but hey ... */ typedef __uint64_t xfs_qcnt_t; typedef __uint16_t xfs_qwarncnt_t; /* * flags for q_flags field in the dquot. */ #define XFS_DQ_USER 0x0001 /* a user quota */ #define XFS_DQ_PROJ 0x0002 /* project quota */ #define XFS_DQ_GROUP 0x0004 /* a group quota */ #define XFS_DQ_DIRTY 0x0008 /* dquot is dirty */ #define XFS_DQ_FREEING 0x0010 /* dquot is beeing torn down */ #define XFS_DQ_ALLTYPES (XFS_DQ_USER|XFS_DQ_PROJ|XFS_DQ_GROUP) #define XFS_DQ_FLAGS \ { XFS_DQ_USER, "USER" }, \ { XFS_DQ_PROJ, "PROJ" }, \ { XFS_DQ_GROUP, "GROUP" }, \ { XFS_DQ_DIRTY, "DIRTY" }, \ { XFS_DQ_FREEING, "FREEING" } /* * We have the possibility of all three quota types being active at once, and * hence free space modification requires modification of all three current * dquots in a single transaction. For this case we need to have a reservation * of at least 3 dquots. * * However, a chmod operation can change both UID and GID in a single * transaction, resulting in requiring {old, new} x {uid, gid} dquots to be * modified. Hence for this case we need to reserve space for at least 4 dquots. * * And in the worst case, there's a rename operation that can be modifying up to * 4 inodes with dquots attached to them. In reality, the only inodes that can * have their dquots modified are the source and destination directory inodes * due to directory name creation and removal. That can require space allocation * and/or freeing on both directory inodes, and hence all three dquots on each * inode can be modified. And if the directories are world writeable, all the * dquots can be unique and so 6 dquots can be modified.... * * And, of course, we also need to take into account the dquot log format item * used to describe each dquot. */ #define XFS_DQUOT_LOGRES(mp) \ ((sizeof(struct xfs_dq_logformat) + sizeof(struct xfs_disk_dquot)) * 6) #define XFS_IS_QUOTA_RUNNING(mp) ((mp)->m_qflags & XFS_ALL_QUOTA_ACCT) #define XFS_IS_UQUOTA_RUNNING(mp) ((mp)->m_qflags & XFS_UQUOTA_ACCT) #define XFS_IS_PQUOTA_RUNNING(mp) ((mp)->m_qflags & XFS_PQUOTA_ACCT) #define XFS_IS_GQUOTA_RUNNING(mp) ((mp)->m_qflags & XFS_GQUOTA_ACCT) #define XFS_IS_UQUOTA_ENFORCED(mp) ((mp)->m_qflags & XFS_UQUOTA_ENFD) #define XFS_IS_GQUOTA_ENFORCED(mp) ((mp)->m_qflags & XFS_GQUOTA_ENFD) #define XFS_IS_PQUOTA_ENFORCED(mp) ((mp)->m_qflags & XFS_PQUOTA_ENFD) /* * Incore only flags for quotaoff - these bits get cleared when quota(s) * are in the process of getting turned off. These flags are in m_qflags but * never in sb_qflags. */ #define XFS_UQUOTA_ACTIVE 0x1000 /* uquotas are being turned off */ #define XFS_GQUOTA_ACTIVE 0x2000 /* gquotas are being turned off */ #define XFS_PQUOTA_ACTIVE 0x4000 /* pquotas are being turned off */ #define XFS_ALL_QUOTA_ACTIVE \ (XFS_UQUOTA_ACTIVE | XFS_GQUOTA_ACTIVE | XFS_PQUOTA_ACTIVE) /* * Checking XFS_IS_*QUOTA_ON() while holding any inode lock guarantees * quota will be not be switched off as long as that inode lock is held. */ #define XFS_IS_QUOTA_ON(mp) ((mp)->m_qflags & (XFS_UQUOTA_ACTIVE | \ XFS_GQUOTA_ACTIVE | \ XFS_PQUOTA_ACTIVE)) #define XFS_IS_UQUOTA_ON(mp) ((mp)->m_qflags & XFS_UQUOTA_ACTIVE) #define XFS_IS_GQUOTA_ON(mp) ((mp)->m_qflags & XFS_GQUOTA_ACTIVE) #define XFS_IS_PQUOTA_ON(mp) ((mp)->m_qflags & XFS_PQUOTA_ACTIVE) /* * Flags to tell various functions what to do. Not all of these are meaningful * to a single function. None of these XFS_QMOPT_* flags are meant to have * persistent values (ie. their values can and will change between versions) */ #define XFS_QMOPT_DQALLOC 0x0000002 /* alloc dquot ondisk if needed */ #define XFS_QMOPT_UQUOTA 0x0000004 /* user dquot requested */ #define XFS_QMOPT_PQUOTA 0x0000008 /* project dquot requested */ #define XFS_QMOPT_FORCE_RES 0x0000010 /* ignore quota limits */ #define XFS_QMOPT_SBVERSION 0x0000040 /* change superblock version num */ #define XFS_QMOPT_DOWARN 0x0000400 /* increase warning cnt if needed */ #define XFS_QMOPT_DQREPAIR 0x0001000 /* repair dquot if damaged */ #define XFS_QMOPT_GQUOTA 0x0002000 /* group dquot requested */ #define XFS_QMOPT_ENOSPC 0x0004000 /* enospc instead of edquot (prj) */ /* * flags to xfs_trans_mod_dquot to indicate which field needs to be * modified. */ #define XFS_QMOPT_RES_REGBLKS 0x0010000 #define XFS_QMOPT_RES_RTBLKS 0x0020000 #define XFS_QMOPT_BCOUNT 0x0040000 #define XFS_QMOPT_ICOUNT 0x0080000 #define XFS_QMOPT_RTBCOUNT 0x0100000 #define XFS_QMOPT_DELBCOUNT 0x0200000 #define XFS_QMOPT_DELRTBCOUNT 0x0400000 #define XFS_QMOPT_RES_INOS 0x0800000 /* * flags for dqalloc. */ #define XFS_QMOPT_INHERIT 0x1000000 /* * flags to xfs_trans_mod_dquot. */ #define XFS_TRANS_DQ_RES_BLKS XFS_QMOPT_RES_REGBLKS #define XFS_TRANS_DQ_RES_RTBLKS XFS_QMOPT_RES_RTBLKS #define XFS_TRANS_DQ_RES_INOS XFS_QMOPT_RES_INOS #define XFS_TRANS_DQ_BCOUNT XFS_QMOPT_BCOUNT #define XFS_TRANS_DQ_DELBCOUNT XFS_QMOPT_DELBCOUNT #define XFS_TRANS_DQ_ICOUNT XFS_QMOPT_ICOUNT #define XFS_TRANS_DQ_RTBCOUNT XFS_QMOPT_RTBCOUNT #define XFS_TRANS_DQ_DELRTBCOUNT XFS_QMOPT_DELRTBCOUNT #define XFS_QMOPT_QUOTALL \ (XFS_QMOPT_UQUOTA | XFS_QMOPT_PQUOTA | XFS_QMOPT_GQUOTA) #define XFS_QMOPT_RESBLK_MASK (XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_RES_RTBLKS) extern int xfs_dqcheck(struct xfs_mount *mp, xfs_disk_dquot_t *ddq, xfs_dqid_t id, uint type, uint flags, char *str); extern int xfs_calc_dquots_per_chunk(unsigned int nbblks); #endif /* __XFS_QUOTA_H__ */ partclone-0.2.86/src/xfs/xfs_rtbitmap.c000066400000000000000000000611641262102574200200440ustar00rootroot00000000000000/* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_bit.h" #include "xfs_mount.h" #include "xfs_inode.h" #include "xfs_bmap.h" #include "xfs_bmap_btree.h" #include "xfs_alloc.h" #include "xfs_trans.h" #include "xfs_trans_space.h" #include "xfs_trace.h" /* * Realtime allocator bitmap functions shared with userspace. */ /* * Get a buffer for the bitmap or summary file block specified. * The buffer is returned read and locked. */ int xfs_rtbuf_get( xfs_mount_t *mp, /* file system mount structure */ xfs_trans_t *tp, /* transaction pointer */ xfs_rtblock_t block, /* block number in bitmap or summary */ int issum, /* is summary not bitmap */ xfs_buf_t **bpp) /* output: buffer for the block */ { xfs_buf_t *bp; /* block buffer, result */ xfs_inode_t *ip; /* bitmap or summary inode */ xfs_bmbt_irec_t map; int nmap = 1; int error; /* error value */ ip = issum ? mp->m_rsumip : mp->m_rbmip; error = xfs_bmapi_read(ip, block, 1, &map, &nmap, XFS_DATA_FORK); if (error) return error; ASSERT(map.br_startblock != NULLFSBLOCK); error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, XFS_FSB_TO_DADDR(mp, map.br_startblock), mp->m_bsize, 0, &bp, NULL); if (error) return error; *bpp = bp; return 0; } /* * Searching backward from start to limit, find the first block whose * allocated/free state is different from start's. */ int xfs_rtfind_back( xfs_mount_t *mp, /* file system mount point */ xfs_trans_t *tp, /* transaction pointer */ xfs_rtblock_t start, /* starting block to look at */ xfs_rtblock_t limit, /* last block to look at */ xfs_rtblock_t *rtblock) /* out: start block found */ { xfs_rtword_t *b; /* current word in buffer */ int bit; /* bit number in the word */ xfs_rtblock_t block; /* bitmap block number */ xfs_buf_t *bp; /* buf for the block */ xfs_rtword_t *bufp; /* starting word in buffer */ int error; /* error value */ xfs_rtblock_t firstbit; /* first useful bit in the word */ xfs_rtblock_t i; /* current bit number rel. to start */ xfs_rtblock_t len; /* length of inspected area */ xfs_rtword_t mask; /* mask of relevant bits for value */ xfs_rtword_t want; /* mask for "good" values */ xfs_rtword_t wdiff; /* difference from wanted value */ int word; /* word number in the buffer */ /* * Compute and read in starting bitmap block for starting block. */ block = XFS_BITTOBLOCK(mp, start); error = xfs_rtbuf_get(mp, tp, block, 0, &bp); if (error) { return error; } bufp = bp->b_addr; /* * Get the first word's index & point to it. */ word = XFS_BITTOWORD(mp, start); b = &bufp[word]; bit = (int)(start & (XFS_NBWORD - 1)); len = start - limit + 1; /* * Compute match value, based on the bit at start: if 1 (free) * then all-ones, else all-zeroes. */ want = (*b & ((xfs_rtword_t)1 << bit)) ? -1 : 0; /* * If the starting position is not word-aligned, deal with the * partial word. */ if (bit < XFS_NBWORD - 1) { /* * Calculate first (leftmost) bit number to look at, * and mask for all the relevant bits in this word. */ firstbit = XFS_RTMAX((xfs_srtblock_t)(bit - len + 1), 0); mask = (((xfs_rtword_t)1 << (bit - firstbit + 1)) - 1) << firstbit; /* * Calculate the difference between the value there * and what we're looking for. */ if ((wdiff = (*b ^ want) & mask)) { /* * Different. Mark where we are and return. */ xfs_trans_brelse(tp, bp); i = bit - XFS_RTHIBIT(wdiff); *rtblock = start - i + 1; return 0; } i = bit - firstbit + 1; /* * Go on to previous block if that's where the previous word is * and we need the previous word. */ if (--word == -1 && i < len) { /* * If done with this block, get the previous one. */ xfs_trans_brelse(tp, bp); error = xfs_rtbuf_get(mp, tp, --block, 0, &bp); if (error) { return error; } bufp = bp->b_addr; word = XFS_BLOCKWMASK(mp); b = &bufp[word]; } else { /* * Go on to the previous word in the buffer. */ b--; } } else { /* * Starting on a word boundary, no partial word. */ i = 0; } /* * Loop over whole words in buffers. When we use up one buffer * we move on to the previous one. */ while (len - i >= XFS_NBWORD) { /* * Compute difference between actual and desired value. */ if ((wdiff = *b ^ want)) { /* * Different, mark where we are and return. */ xfs_trans_brelse(tp, bp); i += XFS_NBWORD - 1 - XFS_RTHIBIT(wdiff); *rtblock = start - i + 1; return 0; } i += XFS_NBWORD; /* * Go on to previous block if that's where the previous word is * and we need the previous word. */ if (--word == -1 && i < len) { /* * If done with this block, get the previous one. */ xfs_trans_brelse(tp, bp); error = xfs_rtbuf_get(mp, tp, --block, 0, &bp); if (error) { return error; } bufp = bp->b_addr; word = XFS_BLOCKWMASK(mp); b = &bufp[word]; } else { /* * Go on to the previous word in the buffer. */ b--; } } /* * If not ending on a word boundary, deal with the last * (partial) word. */ if (len - i) { /* * Calculate first (leftmost) bit number to look at, * and mask for all the relevant bits in this word. */ firstbit = XFS_NBWORD - (len - i); mask = (((xfs_rtword_t)1 << (len - i)) - 1) << firstbit; /* * Compute difference between actual and desired value. */ if ((wdiff = (*b ^ want) & mask)) { /* * Different, mark where we are and return. */ xfs_trans_brelse(tp, bp); i += XFS_NBWORD - 1 - XFS_RTHIBIT(wdiff); *rtblock = start - i + 1; return 0; } else i = len; } /* * No match, return that we scanned the whole area. */ xfs_trans_brelse(tp, bp); *rtblock = start - i + 1; return 0; } /* * Searching forward from start to limit, find the first block whose * allocated/free state is different from start's. */ int xfs_rtfind_forw( xfs_mount_t *mp, /* file system mount point */ xfs_trans_t *tp, /* transaction pointer */ xfs_rtblock_t start, /* starting block to look at */ xfs_rtblock_t limit, /* last block to look at */ xfs_rtblock_t *rtblock) /* out: start block found */ { xfs_rtword_t *b; /* current word in buffer */ int bit; /* bit number in the word */ xfs_rtblock_t block; /* bitmap block number */ xfs_buf_t *bp; /* buf for the block */ xfs_rtword_t *bufp; /* starting word in buffer */ int error; /* error value */ xfs_rtblock_t i; /* current bit number rel. to start */ xfs_rtblock_t lastbit; /* last useful bit in the word */ xfs_rtblock_t len; /* length of inspected area */ xfs_rtword_t mask; /* mask of relevant bits for value */ xfs_rtword_t want; /* mask for "good" values */ xfs_rtword_t wdiff; /* difference from wanted value */ int word; /* word number in the buffer */ /* * Compute and read in starting bitmap block for starting block. */ block = XFS_BITTOBLOCK(mp, start); error = xfs_rtbuf_get(mp, tp, block, 0, &bp); if (error) { return error; } bufp = bp->b_addr; /* * Get the first word's index & point to it. */ word = XFS_BITTOWORD(mp, start); b = &bufp[word]; bit = (int)(start & (XFS_NBWORD - 1)); len = limit - start + 1; /* * Compute match value, based on the bit at start: if 1 (free) * then all-ones, else all-zeroes. */ want = (*b & ((xfs_rtword_t)1 << bit)) ? -1 : 0; /* * If the starting position is not word-aligned, deal with the * partial word. */ if (bit) { /* * Calculate last (rightmost) bit number to look at, * and mask for all the relevant bits in this word. */ lastbit = XFS_RTMIN(bit + len, XFS_NBWORD); mask = (((xfs_rtword_t)1 << (lastbit - bit)) - 1) << bit; /* * Calculate the difference between the value there * and what we're looking for. */ if ((wdiff = (*b ^ want) & mask)) { /* * Different. Mark where we are and return. */ xfs_trans_brelse(tp, bp); i = XFS_RTLOBIT(wdiff) - bit; *rtblock = start + i - 1; return 0; } i = lastbit - bit; /* * Go on to next block if that's where the next word is * and we need the next word. */ if (++word == XFS_BLOCKWSIZE(mp) && i < len) { /* * If done with this block, get the previous one. */ xfs_trans_brelse(tp, bp); error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp); if (error) { return error; } b = bufp = bp->b_addr; word = 0; } else { /* * Go on to the previous word in the buffer. */ b++; } } else { /* * Starting on a word boundary, no partial word. */ i = 0; } /* * Loop over whole words in buffers. When we use up one buffer * we move on to the next one. */ while (len - i >= XFS_NBWORD) { /* * Compute difference between actual and desired value. */ if ((wdiff = *b ^ want)) { /* * Different, mark where we are and return. */ xfs_trans_brelse(tp, bp); i += XFS_RTLOBIT(wdiff); *rtblock = start + i - 1; return 0; } i += XFS_NBWORD; /* * Go on to next block if that's where the next word is * and we need the next word. */ if (++word == XFS_BLOCKWSIZE(mp) && i < len) { /* * If done with this block, get the next one. */ xfs_trans_brelse(tp, bp); error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp); if (error) { return error; } b = bufp = bp->b_addr; word = 0; } else { /* * Go on to the next word in the buffer. */ b++; } } /* * If not ending on a word boundary, deal with the last * (partial) word. */ if ((lastbit = len - i)) { /* * Calculate mask for all the relevant bits in this word. */ mask = ((xfs_rtword_t)1 << lastbit) - 1; /* * Compute difference between actual and desired value. */ if ((wdiff = (*b ^ want) & mask)) { /* * Different, mark where we are and return. */ xfs_trans_brelse(tp, bp); i += XFS_RTLOBIT(wdiff); *rtblock = start + i - 1; return 0; } else i = len; } /* * No match, return that we scanned the whole area. */ xfs_trans_brelse(tp, bp); *rtblock = start + i - 1; return 0; } /* * Read and/or modify the summary information for a given extent size, * bitmap block combination. * Keeps track of a current summary block, so we don't keep reading * it from the buffer cache. * * Summary information is returned in *sum if specified. * If no delta is specified, returns summary only. */ int xfs_rtmodify_summary_int( xfs_mount_t *mp, /* file system mount structure */ xfs_trans_t *tp, /* transaction pointer */ int log, /* log2 of extent size */ xfs_rtblock_t bbno, /* bitmap block number */ int delta, /* change to make to summary info */ xfs_buf_t **rbpp, /* in/out: summary block buffer */ xfs_fsblock_t *rsb, /* in/out: summary block number */ xfs_suminfo_t *sum) /* out: summary info for this block */ { xfs_buf_t *bp; /* buffer for the summary block */ int error; /* error value */ xfs_fsblock_t sb; /* summary fsblock */ int so; /* index into the summary file */ xfs_suminfo_t *sp; /* pointer to returned data */ /* * Compute entry number in the summary file. */ so = XFS_SUMOFFS(mp, log, bbno); /* * Compute the block number in the summary file. */ sb = XFS_SUMOFFSTOBLOCK(mp, so); /* * If we have an old buffer, and the block number matches, use that. */ if (*rbpp && *rsb == sb) bp = *rbpp; /* * Otherwise we have to get the buffer. */ else { /* * If there was an old one, get rid of it first. */ if (*rbpp) xfs_trans_brelse(tp, *rbpp); error = xfs_rtbuf_get(mp, tp, sb, 1, &bp); if (error) { return error; } /* * Remember this buffer and block for the next call. */ *rbpp = bp; *rsb = sb; } /* * Point to the summary information, modify/log it, and/or copy it out. */ sp = XFS_SUMPTR(mp, bp, so); if (delta) { uint first = (uint)((char *)sp - (char *)bp->b_addr); *sp += delta; xfs_trans_log_buf(tp, bp, first, first + sizeof(*sp) - 1); } if (sum) *sum = *sp; return 0; } int xfs_rtmodify_summary( xfs_mount_t *mp, /* file system mount structure */ xfs_trans_t *tp, /* transaction pointer */ int log, /* log2 of extent size */ xfs_rtblock_t bbno, /* bitmap block number */ int delta, /* change to make to summary info */ xfs_buf_t **rbpp, /* in/out: summary block buffer */ xfs_fsblock_t *rsb) /* in/out: summary block number */ { return xfs_rtmodify_summary_int(mp, tp, log, bbno, delta, rbpp, rsb, NULL); } /* * Set the given range of bitmap bits to the given value. * Do whatever I/O and logging is required. */ int xfs_rtmodify_range( xfs_mount_t *mp, /* file system mount point */ xfs_trans_t *tp, /* transaction pointer */ xfs_rtblock_t start, /* starting block to modify */ xfs_extlen_t len, /* length of extent to modify */ int val) /* 1 for free, 0 for allocated */ { xfs_rtword_t *b; /* current word in buffer */ int bit; /* bit number in the word */ xfs_rtblock_t block; /* bitmap block number */ xfs_buf_t *bp; /* buf for the block */ xfs_rtword_t *bufp; /* starting word in buffer */ int error; /* error value */ xfs_rtword_t *first; /* first used word in the buffer */ int i; /* current bit number rel. to start */ int lastbit; /* last useful bit in word */ xfs_rtword_t mask; /* mask o frelevant bits for value */ int word; /* word number in the buffer */ /* * Compute starting bitmap block number. */ block = XFS_BITTOBLOCK(mp, start); /* * Read the bitmap block, and point to its data. */ error = xfs_rtbuf_get(mp, tp, block, 0, &bp); if (error) { return error; } bufp = bp->b_addr; /* * Compute the starting word's address, and starting bit. */ word = XFS_BITTOWORD(mp, start); first = b = &bufp[word]; bit = (int)(start & (XFS_NBWORD - 1)); /* * 0 (allocated) => all zeroes; 1 (free) => all ones. */ val = -val; /* * If not starting on a word boundary, deal with the first * (partial) word. */ if (bit) { /* * Compute first bit not changed and mask of relevant bits. */ lastbit = XFS_RTMIN(bit + len, XFS_NBWORD); mask = (((xfs_rtword_t)1 << (lastbit - bit)) - 1) << bit; /* * Set/clear the active bits. */ if (val) *b |= mask; else *b &= ~mask; i = lastbit - bit; /* * Go on to the next block if that's where the next word is * and we need the next word. */ if (++word == XFS_BLOCKWSIZE(mp) && i < len) { /* * Log the changed part of this block. * Get the next one. */ xfs_trans_log_buf(tp, bp, (uint)((char *)first - (char *)bufp), (uint)((char *)b - (char *)bufp)); error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp); if (error) { return error; } first = b = bufp = bp->b_addr; word = 0; } else { /* * Go on to the next word in the buffer */ b++; } } else { /* * Starting on a word boundary, no partial word. */ i = 0; } /* * Loop over whole words in buffers. When we use up one buffer * we move on to the next one. */ while (len - i >= XFS_NBWORD) { /* * Set the word value correctly. */ *b = val; i += XFS_NBWORD; /* * Go on to the next block if that's where the next word is * and we need the next word. */ if (++word == XFS_BLOCKWSIZE(mp) && i < len) { /* * Log the changed part of this block. * Get the next one. */ xfs_trans_log_buf(tp, bp, (uint)((char *)first - (char *)bufp), (uint)((char *)b - (char *)bufp)); error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp); if (error) { return error; } first = b = bufp = bp->b_addr; word = 0; } else { /* * Go on to the next word in the buffer */ b++; } } /* * If not ending on a word boundary, deal with the last * (partial) word. */ if ((lastbit = len - i)) { /* * Compute a mask of relevant bits. */ bit = 0; mask = ((xfs_rtword_t)1 << lastbit) - 1; /* * Set/clear the active bits. */ if (val) *b |= mask; else *b &= ~mask; b++; } /* * Log any remaining changed bytes. */ if (b > first) xfs_trans_log_buf(tp, bp, (uint)((char *)first - (char *)bufp), (uint)((char *)b - (char *)bufp - 1)); return 0; } /* * Mark an extent specified by start and len freed. * Updates all the summary information as well as the bitmap. */ int xfs_rtfree_range( xfs_mount_t *mp, /* file system mount point */ xfs_trans_t *tp, /* transaction pointer */ xfs_rtblock_t start, /* starting block to free */ xfs_extlen_t len, /* length to free */ xfs_buf_t **rbpp, /* in/out: summary block buffer */ xfs_fsblock_t *rsb) /* in/out: summary block number */ { xfs_rtblock_t end; /* end of the freed extent */ int error; /* error value */ xfs_rtblock_t postblock; /* first block freed > end */ xfs_rtblock_t preblock; /* first block freed < start */ end = start + len - 1; /* * Modify the bitmap to mark this extent freed. */ error = xfs_rtmodify_range(mp, tp, start, len, 1); if (error) { return error; } /* * Assume we're freeing out of the middle of an allocated extent. * We need to find the beginning and end of the extent so we can * properly update the summary. */ error = xfs_rtfind_back(mp, tp, start, 0, &preblock); if (error) { return error; } /* * Find the next allocated block (end of allocated extent). */ error = xfs_rtfind_forw(mp, tp, end, mp->m_sb.sb_rextents - 1, &postblock); if (error) return error; /* * If there are blocks not being freed at the front of the * old extent, add summary data for them to be allocated. */ if (preblock < start) { error = xfs_rtmodify_summary(mp, tp, XFS_RTBLOCKLOG(start - preblock), XFS_BITTOBLOCK(mp, preblock), -1, rbpp, rsb); if (error) { return error; } } /* * If there are blocks not being freed at the end of the * old extent, add summary data for them to be allocated. */ if (postblock > end) { error = xfs_rtmodify_summary(mp, tp, XFS_RTBLOCKLOG(postblock - end), XFS_BITTOBLOCK(mp, end + 1), -1, rbpp, rsb); if (error) { return error; } } /* * Increment the summary information corresponding to the entire * (new) free extent. */ error = xfs_rtmodify_summary(mp, tp, XFS_RTBLOCKLOG(postblock + 1 - preblock), XFS_BITTOBLOCK(mp, preblock), 1, rbpp, rsb); return error; } /* * Check that the given range is either all allocated (val = 0) or * all free (val = 1). */ int xfs_rtcheck_range( xfs_mount_t *mp, /* file system mount point */ xfs_trans_t *tp, /* transaction pointer */ xfs_rtblock_t start, /* starting block number of extent */ xfs_extlen_t len, /* length of extent */ int val, /* 1 for free, 0 for allocated */ xfs_rtblock_t *new, /* out: first block not matching */ int *stat) /* out: 1 for matches, 0 for not */ { xfs_rtword_t *b; /* current word in buffer */ int bit; /* bit number in the word */ xfs_rtblock_t block; /* bitmap block number */ xfs_buf_t *bp; /* buf for the block */ xfs_rtword_t *bufp; /* starting word in buffer */ int error; /* error value */ xfs_rtblock_t i; /* current bit number rel. to start */ xfs_rtblock_t lastbit; /* last useful bit in word */ xfs_rtword_t mask; /* mask of relevant bits for value */ xfs_rtword_t wdiff; /* difference from wanted value */ int word; /* word number in the buffer */ /* * Compute starting bitmap block number */ block = XFS_BITTOBLOCK(mp, start); /* * Read the bitmap block. */ error = xfs_rtbuf_get(mp, tp, block, 0, &bp); if (error) { return error; } bufp = bp->b_addr; /* * Compute the starting word's address, and starting bit. */ word = XFS_BITTOWORD(mp, start); b = &bufp[word]; bit = (int)(start & (XFS_NBWORD - 1)); /* * 0 (allocated) => all zero's; 1 (free) => all one's. */ val = -val; /* * If not starting on a word boundary, deal with the first * (partial) word. */ if (bit) { /* * Compute first bit not examined. */ lastbit = XFS_RTMIN(bit + len, XFS_NBWORD); /* * Mask of relevant bits. */ mask = (((xfs_rtword_t)1 << (lastbit - bit)) - 1) << bit; /* * Compute difference between actual and desired value. */ if ((wdiff = (*b ^ val) & mask)) { /* * Different, compute first wrong bit and return. */ xfs_trans_brelse(tp, bp); i = XFS_RTLOBIT(wdiff) - bit; *new = start + i; *stat = 0; return 0; } i = lastbit - bit; /* * Go on to next block if that's where the next word is * and we need the next word. */ if (++word == XFS_BLOCKWSIZE(mp) && i < len) { /* * If done with this block, get the next one. */ xfs_trans_brelse(tp, bp); error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp); if (error) { return error; } b = bufp = bp->b_addr; word = 0; } else { /* * Go on to the next word in the buffer. */ b++; } } else { /* * Starting on a word boundary, no partial word. */ i = 0; } /* * Loop over whole words in buffers. When we use up one buffer * we move on to the next one. */ while (len - i >= XFS_NBWORD) { /* * Compute difference between actual and desired value. */ if ((wdiff = *b ^ val)) { /* * Different, compute first wrong bit and return. */ xfs_trans_brelse(tp, bp); i += XFS_RTLOBIT(wdiff); *new = start + i; *stat = 0; return 0; } i += XFS_NBWORD; /* * Go on to next block if that's where the next word is * and we need the next word. */ if (++word == XFS_BLOCKWSIZE(mp) && i < len) { /* * If done with this block, get the next one. */ xfs_trans_brelse(tp, bp); error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp); if (error) { return error; } b = bufp = bp->b_addr; word = 0; } else { /* * Go on to the next word in the buffer. */ b++; } } /* * If not ending on a word boundary, deal with the last * (partial) word. */ if ((lastbit = len - i)) { /* * Mask of relevant bits. */ mask = ((xfs_rtword_t)1 << lastbit) - 1; /* * Compute difference between actual and desired value. */ if ((wdiff = (*b ^ val) & mask)) { /* * Different, compute first wrong bit and return. */ xfs_trans_brelse(tp, bp); i += XFS_RTLOBIT(wdiff); *new = start + i; *stat = 0; return 0; } else i = len; } /* * Successful, return. */ xfs_trans_brelse(tp, bp); *new = start + i; *stat = 1; return 0; } #ifdef DEBUG /* * Check that the given extent (block range) is allocated already. */ STATIC int /* error */ xfs_rtcheck_alloc_range( xfs_mount_t *mp, /* file system mount point */ xfs_trans_t *tp, /* transaction pointer */ xfs_rtblock_t bno, /* starting block number of extent */ xfs_extlen_t len) /* length of extent */ { xfs_rtblock_t new; /* dummy for xfs_rtcheck_range */ int stat; int error; error = xfs_rtcheck_range(mp, tp, bno, len, 0, &new, &stat); if (error) return error; ASSERT(stat); return 0; } #else #define xfs_rtcheck_alloc_range(m,t,b,l) (0) #endif /* * Free an extent in the realtime subvolume. Length is expressed in * realtime extents, as is the block number. */ int /* error */ xfs_rtfree_extent( xfs_trans_t *tp, /* transaction pointer */ xfs_rtblock_t bno, /* starting block number to free */ xfs_extlen_t len) /* length of extent freed */ { int error; /* error value */ xfs_mount_t *mp; /* file system mount structure */ xfs_fsblock_t sb; /* summary file block number */ xfs_buf_t *sumbp = NULL; /* summary file block buffer */ mp = tp->t_mountp; ASSERT(mp->m_rbmip->i_itemp != NULL); ASSERT(xfs_isilocked(mp->m_rbmip, XFS_ILOCK_EXCL)); error = xfs_rtcheck_alloc_range(mp, tp, bno, len); if (error) return error; /* * Free the range of realtime blocks. */ error = xfs_rtfree_range(mp, tp, bno, len, &sumbp, &sb); if (error) { return error; } /* * Mark more blocks free in the superblock. */ xfs_trans_mod_sb(tp, XFS_TRANS_SB_FREXTENTS, (long)len); /* * If we've now freed all the blocks, reset the file sequence * number to 0. */ if (tp->t_frextents_delta + mp->m_sb.sb_frextents == mp->m_sb.sb_rextents) { if (!(mp->m_rbmip->i_d.di_flags & XFS_DIFLAG_NEWRTBM)) mp->m_rbmip->i_d.di_flags |= XFS_DIFLAG_NEWRTBM; *(__uint64_t *)&mp->m_rbmip->i_d.di_atime = 0; xfs_trans_log_inode(tp, mp->m_rbmip, XFS_ILOG_CORE); } return 0; } partclone-0.2.86/src/xfs/xfs_sb.c000066400000000000000000000617331262102574200166300ustar00rootroot00000000000000/* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_bit.h" #include "xfs_sb.h" #include "xfs_mount.h" #include "xfs_inode.h" #include "xfs_ialloc.h" #include "xfs_alloc.h" #include "xfs_trace.h" #include "xfs_cksum.h" #include "xfs_trans.h" #include "xfs_bmap_btree.h" #include "xfs_alloc_btree.h" #include "xfs_ialloc_btree.h" /* * Physical superblock buffer manipulations. Shared with libxfs in userspace. */ /* * Reference counting access wrappers to the perag structures. * Because we never free per-ag structures, the only thing we * have to protect against changes is the tree structure itself. */ struct xfs_perag * xfs_perag_get( struct xfs_mount *mp, xfs_agnumber_t agno) { struct xfs_perag *pag; int ref = 0; rcu_read_lock(); pag = radix_tree_lookup(&mp->m_perag_tree, agno); if (pag) { ASSERT(atomic_read(&pag->pag_ref) >= 0); ref = atomic_inc_return(&pag->pag_ref); } rcu_read_unlock(); trace_xfs_perag_get(mp, agno, ref, _RET_IP_); return pag; } /* * search from @first to find the next perag with the given tag set. */ struct xfs_perag * xfs_perag_get_tag( struct xfs_mount *mp, xfs_agnumber_t first, int tag) { struct xfs_perag *pag; int found; int ref; rcu_read_lock(); found = radix_tree_gang_lookup_tag(&mp->m_perag_tree, (void **)&pag, first, 1, tag); if (found <= 0) { rcu_read_unlock(); return NULL; } ref = atomic_inc_return(&pag->pag_ref); rcu_read_unlock(); trace_xfs_perag_get_tag(mp, pag->pag_agno, ref, _RET_IP_); return pag; } void xfs_perag_put( struct xfs_perag *pag) { int ref; ASSERT(atomic_read(&pag->pag_ref) > 0); ref = atomic_dec_return(&pag->pag_ref); trace_xfs_perag_put(pag->pag_mount, pag->pag_agno, ref, _RET_IP_); } /* * Check the validity of the SB found. */ STATIC int xfs_mount_validate_sb( xfs_mount_t *mp, xfs_sb_t *sbp, bool check_inprogress, bool check_version) { if (sbp->sb_magicnum != XFS_SB_MAGIC) { xfs_warn(mp, "bad magic number"); return -EWRONGFS; } if (!xfs_sb_good_version(sbp)) { xfs_warn(mp, "bad version"); return -EWRONGFS; } /* * Version 5 superblock feature mask validation. Reject combinations the * kernel cannot support up front before checking anything else. For * write validation, we don't need to check feature masks. */ if (check_version && XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) { if (xfs_sb_has_compat_feature(sbp, XFS_SB_FEAT_COMPAT_UNKNOWN)) { xfs_warn(mp, "Superblock has unknown compatible features (0x%x) enabled.", (sbp->sb_features_compat & XFS_SB_FEAT_COMPAT_UNKNOWN)); xfs_warn(mp, "Using a more recent kernel is recommended."); } if (xfs_sb_has_ro_compat_feature(sbp, XFS_SB_FEAT_RO_COMPAT_UNKNOWN)) { xfs_alert(mp, "Superblock has unknown read-only compatible features (0x%x) enabled.", (sbp->sb_features_ro_compat & XFS_SB_FEAT_RO_COMPAT_UNKNOWN)); if (!(mp->m_flags & XFS_MOUNT_RDONLY)) { xfs_warn(mp, "Attempted to mount read-only compatible filesystem read-write."); xfs_warn(mp, "Filesystem can only be safely mounted read only."); return -EINVAL; } } if (xfs_sb_has_incompat_feature(sbp, XFS_SB_FEAT_INCOMPAT_UNKNOWN)) { xfs_warn(mp, "Superblock has unknown incompatible features (0x%x) enabled.", (sbp->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_UNKNOWN)); xfs_warn(mp, "Filesystem can not be safely mounted by this kernel."); return -EINVAL; } } if (xfs_sb_version_has_pquotino(sbp)) { if (sbp->sb_qflags & (XFS_OQUOTA_ENFD | XFS_OQUOTA_CHKD)) { xfs_notice(mp, "Version 5 of Super block has XFS_OQUOTA bits."); return -EFSCORRUPTED; } } else if (sbp->sb_qflags & (XFS_PQUOTA_ENFD | XFS_GQUOTA_ENFD | XFS_PQUOTA_CHKD | XFS_GQUOTA_CHKD)) { xfs_notice(mp, "Superblock earlier than Version 5 has XFS_[PQ]UOTA_{ENFD|CHKD} bits."); return -EFSCORRUPTED; } /* * Full inode chunks must be aligned to inode chunk size when * sparse inodes are enabled to support the sparse chunk * allocation algorithm and prevent overlapping inode records. */ if (xfs_sb_version_hassparseinodes(sbp)) { uint32_t align; align = XFS_INODES_PER_CHUNK * sbp->sb_inodesize >> sbp->sb_blocklog; if (sbp->sb_inoalignmt != align) { xfs_warn(mp, "Inode block alignment (%u) must match chunk size (%u) for sparse inodes.", sbp->sb_inoalignmt, align); return -EINVAL; } } if (unlikely( sbp->sb_logstart == 0 && mp->m_logdev_targp == mp->m_ddev_targp)) { xfs_warn(mp, "filesystem is marked as having an external log; " "specify logdev on the mount command line."); return -EINVAL; } if (unlikely( sbp->sb_logstart != 0 && mp->m_logdev_targp != mp->m_ddev_targp)) { xfs_warn(mp, "filesystem is marked as having an internal log; " "do not specify logdev on the mount command line."); return -EINVAL; } /* * More sanity checking. Most of these were stolen directly from * xfs_repair. */ if (unlikely( sbp->sb_agcount <= 0 || sbp->sb_sectsize < XFS_MIN_SECTORSIZE || sbp->sb_sectsize > XFS_MAX_SECTORSIZE || sbp->sb_sectlog < XFS_MIN_SECTORSIZE_LOG || sbp->sb_sectlog > XFS_MAX_SECTORSIZE_LOG || sbp->sb_sectsize != (1 << sbp->sb_sectlog) || sbp->sb_blocksize < XFS_MIN_BLOCKSIZE || sbp->sb_blocksize > XFS_MAX_BLOCKSIZE || sbp->sb_blocklog < XFS_MIN_BLOCKSIZE_LOG || sbp->sb_blocklog > XFS_MAX_BLOCKSIZE_LOG || sbp->sb_blocksize != (1 << sbp->sb_blocklog) || sbp->sb_dirblklog > XFS_MAX_BLOCKSIZE_LOG || sbp->sb_inodesize < XFS_DINODE_MIN_SIZE || sbp->sb_inodesize > XFS_DINODE_MAX_SIZE || sbp->sb_inodelog < XFS_DINODE_MIN_LOG || sbp->sb_inodelog > XFS_DINODE_MAX_LOG || sbp->sb_inodesize != (1 << sbp->sb_inodelog) || sbp->sb_logsunit > XLOG_MAX_RECORD_BSIZE || sbp->sb_inopblock != howmany(sbp->sb_blocksize,sbp->sb_inodesize) || (sbp->sb_blocklog - sbp->sb_inodelog != sbp->sb_inopblog) || (sbp->sb_rextsize * sbp->sb_blocksize > XFS_MAX_RTEXTSIZE) || (sbp->sb_rextsize * sbp->sb_blocksize < XFS_MIN_RTEXTSIZE) || (sbp->sb_imax_pct > 100 /* zero sb_imax_pct is valid */) || sbp->sb_dblocks == 0 || sbp->sb_dblocks > XFS_MAX_DBLOCKS(sbp) || sbp->sb_dblocks < XFS_MIN_DBLOCKS(sbp) || sbp->sb_shared_vn != 0)) { xfs_notice(mp, "SB sanity check failed"); return -EFSCORRUPTED; } /* * Currently only very few inode sizes are supported. */ switch (sbp->sb_inodesize) { case 256: case 512: case 1024: case 2048: break; default: xfs_warn(mp, "inode size of %d bytes not supported", sbp->sb_inodesize); return -ENOSYS; } if (xfs_sb_validate_fsb_count(sbp, sbp->sb_dblocks) || xfs_sb_validate_fsb_count(sbp, sbp->sb_rblocks)) { xfs_warn(mp, "file system too large to be mounted on this system."); return -EFBIG; } return 0; } void xfs_sb_quota_from_disk(struct xfs_sb *sbp) { /* * older mkfs doesn't initialize quota inodes to NULLFSINO. This * leads to in-core values having two different values for a quota * inode to be invalid: 0 and NULLFSINO. Change it to a single value * NULLFSINO. * * Note that this change affect only the in-core values. These * values are not written back to disk unless any quota information * is written to the disk. Even in that case, sb_pquotino field is * not written to disk unless the superblock supports pquotino. */ if (sbp->sb_uquotino == 0) sbp->sb_uquotino = NULLFSINO; if (sbp->sb_gquotino == 0) sbp->sb_gquotino = NULLFSINO; if (sbp->sb_pquotino == 0) sbp->sb_pquotino = NULLFSINO; /* * We need to do these manipilations only if we are working * with an older version of on-disk superblock. */ if (xfs_sb_version_has_pquotino(sbp)) return; if (sbp->sb_qflags & XFS_OQUOTA_ENFD) sbp->sb_qflags |= (sbp->sb_qflags & XFS_PQUOTA_ACCT) ? XFS_PQUOTA_ENFD : XFS_GQUOTA_ENFD; if (sbp->sb_qflags & XFS_OQUOTA_CHKD) sbp->sb_qflags |= (sbp->sb_qflags & XFS_PQUOTA_ACCT) ? XFS_PQUOTA_CHKD : XFS_GQUOTA_CHKD; sbp->sb_qflags &= ~(XFS_OQUOTA_ENFD | XFS_OQUOTA_CHKD); if (sbp->sb_qflags & XFS_PQUOTA_ACCT) { /* * In older version of superblock, on-disk superblock only * has sb_gquotino, and in-core superblock has both sb_gquotino * and sb_pquotino. But, only one of them is supported at any * point of time. So, if PQUOTA is set in disk superblock, * copy over sb_gquotino to sb_pquotino. */ sbp->sb_pquotino = sbp->sb_gquotino; sbp->sb_gquotino = NULLFSINO; } } static void __xfs_sb_from_disk( struct xfs_sb *to, xfs_dsb_t *from, bool convert_xquota) { to->sb_magicnum = be32_to_cpu(from->sb_magicnum); to->sb_blocksize = be32_to_cpu(from->sb_blocksize); to->sb_dblocks = be64_to_cpu(from->sb_dblocks); to->sb_rblocks = be64_to_cpu(from->sb_rblocks); to->sb_rextents = be64_to_cpu(from->sb_rextents); memcpy(&to->sb_uuid, &from->sb_uuid, sizeof(to->sb_uuid)); to->sb_logstart = be64_to_cpu(from->sb_logstart); to->sb_rootino = be64_to_cpu(from->sb_rootino); to->sb_rbmino = be64_to_cpu(from->sb_rbmino); to->sb_rsumino = be64_to_cpu(from->sb_rsumino); to->sb_rextsize = be32_to_cpu(from->sb_rextsize); to->sb_agblocks = be32_to_cpu(from->sb_agblocks); to->sb_agcount = be32_to_cpu(from->sb_agcount); to->sb_rbmblocks = be32_to_cpu(from->sb_rbmblocks); to->sb_logblocks = be32_to_cpu(from->sb_logblocks); to->sb_versionnum = be16_to_cpu(from->sb_versionnum); to->sb_sectsize = be16_to_cpu(from->sb_sectsize); to->sb_inodesize = be16_to_cpu(from->sb_inodesize); to->sb_inopblock = be16_to_cpu(from->sb_inopblock); memcpy(&to->sb_fname, &from->sb_fname, sizeof(to->sb_fname)); to->sb_blocklog = from->sb_blocklog; to->sb_sectlog = from->sb_sectlog; to->sb_inodelog = from->sb_inodelog; to->sb_inopblog = from->sb_inopblog; to->sb_agblklog = from->sb_agblklog; to->sb_rextslog = from->sb_rextslog; to->sb_inprogress = from->sb_inprogress; to->sb_imax_pct = from->sb_imax_pct; to->sb_icount = be64_to_cpu(from->sb_icount); to->sb_ifree = be64_to_cpu(from->sb_ifree); to->sb_fdblocks = be64_to_cpu(from->sb_fdblocks); to->sb_frextents = be64_to_cpu(from->sb_frextents); to->sb_uquotino = be64_to_cpu(from->sb_uquotino); to->sb_gquotino = be64_to_cpu(from->sb_gquotino); to->sb_qflags = be16_to_cpu(from->sb_qflags); to->sb_flags = from->sb_flags; to->sb_shared_vn = from->sb_shared_vn; to->sb_inoalignmt = be32_to_cpu(from->sb_inoalignmt); to->sb_unit = be32_to_cpu(from->sb_unit); to->sb_width = be32_to_cpu(from->sb_width); to->sb_dirblklog = from->sb_dirblklog; to->sb_logsectlog = from->sb_logsectlog; to->sb_logsectsize = be16_to_cpu(from->sb_logsectsize); to->sb_logsunit = be32_to_cpu(from->sb_logsunit); to->sb_features2 = be32_to_cpu(from->sb_features2); to->sb_bad_features2 = be32_to_cpu(from->sb_bad_features2); to->sb_features_compat = be32_to_cpu(from->sb_features_compat); to->sb_features_ro_compat = be32_to_cpu(from->sb_features_ro_compat); to->sb_features_incompat = be32_to_cpu(from->sb_features_incompat); to->sb_features_log_incompat = be32_to_cpu(from->sb_features_log_incompat); /* crc is only used on disk, not in memory; just init to 0 here. */ to->sb_crc = 0; to->sb_spino_align = be32_to_cpu(from->sb_spino_align); to->sb_pquotino = be64_to_cpu(from->sb_pquotino); to->sb_lsn = be64_to_cpu(from->sb_lsn); /* * sb_meta_uuid is only on disk if it differs from sb_uuid and the * feature flag is set; if not set we keep it only in memory. */ if (xfs_sb_version_hasmetauuid(to)) uuid_copy(&to->sb_meta_uuid, &from->sb_meta_uuid); else uuid_copy(&to->sb_meta_uuid, &from->sb_uuid); /* Convert on-disk flags to in-memory flags? */ if (convert_xquota) xfs_sb_quota_from_disk(to); } void xfs_sb_from_disk( struct xfs_sb *to, xfs_dsb_t *from) { __xfs_sb_from_disk(to, from, true); } static void xfs_sb_quota_to_disk( struct xfs_dsb *to, struct xfs_sb *from) { __uint16_t qflags = from->sb_qflags; to->sb_uquotino = cpu_to_be64(from->sb_uquotino); if (xfs_sb_version_has_pquotino(from)) { to->sb_qflags = cpu_to_be16(from->sb_qflags); to->sb_gquotino = cpu_to_be64(from->sb_gquotino); to->sb_pquotino = cpu_to_be64(from->sb_pquotino); return; } /* * The in-core version of sb_qflags do not have XFS_OQUOTA_* * flags, whereas the on-disk version does. So, convert incore * XFS_{PG}QUOTA_* flags to on-disk XFS_OQUOTA_* flags. */ qflags &= ~(XFS_PQUOTA_ENFD | XFS_PQUOTA_CHKD | XFS_GQUOTA_ENFD | XFS_GQUOTA_CHKD); if (from->sb_qflags & (XFS_PQUOTA_ENFD | XFS_GQUOTA_ENFD)) qflags |= XFS_OQUOTA_ENFD; if (from->sb_qflags & (XFS_PQUOTA_CHKD | XFS_GQUOTA_CHKD)) qflags |= XFS_OQUOTA_CHKD; to->sb_qflags = cpu_to_be16(qflags); /* * GQUOTINO and PQUOTINO cannot be used together in versions * of superblock that do not have pquotino. from->sb_flags * tells us which quota is active and should be copied to * disk. If neither are active, we should NULL the inode. * * In all cases, the separate pquotino must remain 0 because it * it beyond the "end" of the valid non-pquotino superblock. */ if (from->sb_qflags & XFS_GQUOTA_ACCT) to->sb_gquotino = cpu_to_be64(from->sb_gquotino); else if (from->sb_qflags & XFS_PQUOTA_ACCT) to->sb_gquotino = cpu_to_be64(from->sb_pquotino); else { /* * We can't rely on just the fields being logged to tell us * that it is safe to write NULLFSINO - we should only do that * if quotas are not actually enabled. Hence only write * NULLFSINO if both in-core quota inodes are NULL. */ if (from->sb_gquotino == NULLFSINO && from->sb_pquotino == NULLFSINO) to->sb_gquotino = cpu_to_be64(NULLFSINO); } to->sb_pquotino = 0; } void xfs_sb_to_disk( struct xfs_dsb *to, struct xfs_sb *from) { xfs_sb_quota_to_disk(to, from); to->sb_magicnum = cpu_to_be32(from->sb_magicnum); to->sb_blocksize = cpu_to_be32(from->sb_blocksize); to->sb_dblocks = cpu_to_be64(from->sb_dblocks); to->sb_rblocks = cpu_to_be64(from->sb_rblocks); to->sb_rextents = cpu_to_be64(from->sb_rextents); memcpy(&to->sb_uuid, &from->sb_uuid, sizeof(to->sb_uuid)); to->sb_logstart = cpu_to_be64(from->sb_logstart); to->sb_rootino = cpu_to_be64(from->sb_rootino); to->sb_rbmino = cpu_to_be64(from->sb_rbmino); to->sb_rsumino = cpu_to_be64(from->sb_rsumino); to->sb_rextsize = cpu_to_be32(from->sb_rextsize); to->sb_agblocks = cpu_to_be32(from->sb_agblocks); to->sb_agcount = cpu_to_be32(from->sb_agcount); to->sb_rbmblocks = cpu_to_be32(from->sb_rbmblocks); to->sb_logblocks = cpu_to_be32(from->sb_logblocks); to->sb_versionnum = cpu_to_be16(from->sb_versionnum); to->sb_sectsize = cpu_to_be16(from->sb_sectsize); to->sb_inodesize = cpu_to_be16(from->sb_inodesize); to->sb_inopblock = cpu_to_be16(from->sb_inopblock); memcpy(&to->sb_fname, &from->sb_fname, sizeof(to->sb_fname)); to->sb_blocklog = from->sb_blocklog; to->sb_sectlog = from->sb_sectlog; to->sb_inodelog = from->sb_inodelog; to->sb_inopblog = from->sb_inopblog; to->sb_agblklog = from->sb_agblklog; to->sb_rextslog = from->sb_rextslog; to->sb_inprogress = from->sb_inprogress; to->sb_imax_pct = from->sb_imax_pct; to->sb_icount = cpu_to_be64(from->sb_icount); to->sb_ifree = cpu_to_be64(from->sb_ifree); to->sb_fdblocks = cpu_to_be64(from->sb_fdblocks); to->sb_frextents = cpu_to_be64(from->sb_frextents); to->sb_flags = from->sb_flags; to->sb_shared_vn = from->sb_shared_vn; to->sb_inoalignmt = cpu_to_be32(from->sb_inoalignmt); to->sb_unit = cpu_to_be32(from->sb_unit); to->sb_width = cpu_to_be32(from->sb_width); to->sb_dirblklog = from->sb_dirblklog; to->sb_logsectlog = from->sb_logsectlog; to->sb_logsectsize = cpu_to_be16(from->sb_logsectsize); to->sb_logsunit = cpu_to_be32(from->sb_logsunit); /* * We need to ensure that bad_features2 always matches features2. * Hence we enforce that here rather than having to remember to do it * everywhere else that updates features2. */ from->sb_bad_features2 = from->sb_features2; to->sb_features2 = cpu_to_be32(from->sb_features2); to->sb_bad_features2 = cpu_to_be32(from->sb_bad_features2); if (xfs_sb_version_hascrc(from)) { to->sb_features_compat = cpu_to_be32(from->sb_features_compat); to->sb_features_ro_compat = cpu_to_be32(from->sb_features_ro_compat); to->sb_features_incompat = cpu_to_be32(from->sb_features_incompat); to->sb_features_log_incompat = cpu_to_be32(from->sb_features_log_incompat); to->sb_spino_align = cpu_to_be32(from->sb_spino_align); to->sb_lsn = cpu_to_be64(from->sb_lsn); if (xfs_sb_version_hasmetauuid(from)) uuid_copy(&to->sb_meta_uuid, &from->sb_meta_uuid); } } static int xfs_sb_verify( struct xfs_buf *bp, bool check_version) { struct xfs_mount *mp = bp->b_target->bt_mount; struct xfs_sb sb; /* * Use call variant which doesn't convert quota flags from disk * format, because xfs_mount_validate_sb checks the on-disk flags. */ __xfs_sb_from_disk(&sb, XFS_BUF_TO_SBP(bp), false); /* * Only check the in progress field for the primary superblock as * mkfs.xfs doesn't clear it from secondary superblocks. */ return xfs_mount_validate_sb(mp, &sb, bp->b_bn == XFS_SB_DADDR, check_version); } /* * If the superblock has the CRC feature bit set or the CRC field is non-null, * check that the CRC is valid. We check the CRC field is non-null because a * single bit error could clear the feature bit and unused parts of the * superblock are supposed to be zero. Hence a non-null crc field indicates that * we've potentially lost a feature bit and we should check it anyway. * * However, past bugs (i.e. in growfs) left non-zeroed regions beyond the * last field in V4 secondary superblocks. So for secondary superblocks, * we are more forgiving, and ignore CRC failures if the primary doesn't * indicate that the fs version is V5. */ static void xfs_sb_read_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_target->bt_mount; struct xfs_dsb *dsb = XFS_BUF_TO_SBP(bp); int error; /* * open code the version check to avoid needing to convert the entire * superblock from disk order just to check the version number */ if (dsb->sb_magicnum == cpu_to_be32(XFS_SB_MAGIC) && (((be16_to_cpu(dsb->sb_versionnum) & XFS_SB_VERSION_NUMBITS) == XFS_SB_VERSION_5) || dsb->sb_crc != 0)) { if (!xfs_buf_verify_cksum(bp, XFS_SB_CRC_OFF)) { /* Only fail bad secondaries on a known V5 filesystem */ if (bp->b_bn == XFS_SB_DADDR || xfs_sb_version_hascrc(&mp->m_sb)) { error = -EFSBADCRC; goto out_error; } } } error = xfs_sb_verify(bp, true); out_error: if (error) { xfs_buf_ioerror(bp, error); if (error == -EFSCORRUPTED || error == -EFSBADCRC) xfs_verifier_error(bp); } } /* * We may be probed for a filesystem match, so we may not want to emit * messages when the superblock buffer is not actually an XFS superblock. * If we find an XFS superblock, then run a normal, noisy mount because we are * really going to mount it and want to know about errors. */ static void xfs_sb_quiet_read_verify( struct xfs_buf *bp) { struct xfs_dsb *dsb = XFS_BUF_TO_SBP(bp); if (dsb->sb_magicnum == cpu_to_be32(XFS_SB_MAGIC)) { /* XFS filesystem, verify noisily! */ xfs_sb_read_verify(bp); return; } /* quietly fail */ xfs_buf_ioerror(bp, -EWRONGFS); } static void xfs_sb_write_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_target->bt_mount; struct xfs_buf_log_item *bip = bp->b_fspriv; int error; error = xfs_sb_verify(bp, false); if (error) { xfs_buf_ioerror(bp, error); xfs_verifier_error(bp); return; } if (!xfs_sb_version_hascrc(&mp->m_sb)) return; if (bip) XFS_BUF_TO_SBP(bp)->sb_lsn = cpu_to_be64(bip->bli_item.li_lsn); xfs_buf_update_cksum(bp, XFS_SB_CRC_OFF); } const struct xfs_buf_ops xfs_sb_buf_ops = { .verify_read = xfs_sb_read_verify, .verify_write = xfs_sb_write_verify, }; const struct xfs_buf_ops xfs_sb_quiet_buf_ops = { .verify_read = xfs_sb_quiet_read_verify, .verify_write = xfs_sb_write_verify, }; /* * xfs_mount_common * * Mount initialization code establishing various mount * fields from the superblock associated with the given * mount structure */ void xfs_sb_mount_common( struct xfs_mount *mp, struct xfs_sb *sbp) { mp->m_agfrotor = mp->m_agirotor = 0; spin_lock_init(&mp->m_agirotor_lock); mp->m_maxagi = mp->m_sb.sb_agcount; mp->m_blkbit_log = sbp->sb_blocklog + XFS_NBBYLOG; mp->m_blkbb_log = sbp->sb_blocklog - BBSHIFT; mp->m_sectbb_log = sbp->sb_sectlog - BBSHIFT; mp->m_agno_log = xfs_highbit32(sbp->sb_agcount - 1) + 1; mp->m_agino_log = sbp->sb_inopblog + sbp->sb_agblklog; mp->m_blockmask = sbp->sb_blocksize - 1; mp->m_blockwsize = sbp->sb_blocksize >> XFS_WORDLOG; mp->m_blockwmask = mp->m_blockwsize - 1; mp->m_alloc_mxr[0] = xfs_allocbt_maxrecs(mp, sbp->sb_blocksize, 1); mp->m_alloc_mxr[1] = xfs_allocbt_maxrecs(mp, sbp->sb_blocksize, 0); mp->m_alloc_mnr[0] = mp->m_alloc_mxr[0] / 2; mp->m_alloc_mnr[1] = mp->m_alloc_mxr[1] / 2; mp->m_inobt_mxr[0] = xfs_inobt_maxrecs(mp, sbp->sb_blocksize, 1); mp->m_inobt_mxr[1] = xfs_inobt_maxrecs(mp, sbp->sb_blocksize, 0); mp->m_inobt_mnr[0] = mp->m_inobt_mxr[0] / 2; mp->m_inobt_mnr[1] = mp->m_inobt_mxr[1] / 2; mp->m_bmap_dmxr[0] = xfs_bmbt_maxrecs(mp, sbp->sb_blocksize, 1); mp->m_bmap_dmxr[1] = xfs_bmbt_maxrecs(mp, sbp->sb_blocksize, 0); mp->m_bmap_dmnr[0] = mp->m_bmap_dmxr[0] / 2; mp->m_bmap_dmnr[1] = mp->m_bmap_dmxr[1] / 2; mp->m_bsize = XFS_FSB_TO_BB(mp, 1); mp->m_ialloc_inos = (int)MAX((__uint16_t)XFS_INODES_PER_CHUNK, sbp->sb_inopblock); mp->m_ialloc_blks = mp->m_ialloc_inos >> sbp->sb_inopblog; if (sbp->sb_spino_align) mp->m_ialloc_min_blks = sbp->sb_spino_align; else mp->m_ialloc_min_blks = mp->m_ialloc_blks; } /* * xfs_initialize_perag_data * * Read in each per-ag structure so we can count up the number of * allocated inodes, free inodes and used filesystem blocks as this * information is no longer persistent in the superblock. Once we have * this information, write it into the in-core superblock structure. */ int xfs_initialize_perag_data( struct xfs_mount *mp, xfs_agnumber_t agcount) { xfs_agnumber_t index; xfs_perag_t *pag; xfs_sb_t *sbp = &mp->m_sb; uint64_t ifree = 0; uint64_t ialloc = 0; uint64_t bfree = 0; uint64_t bfreelst = 0; uint64_t btree = 0; int error; for (index = 0; index < agcount; index++) { /* * read the agf, then the agi. This gets us * all the information we need and populates the * per-ag structures for us. */ error = xfs_alloc_pagf_init(mp, NULL, index, 0); if (error) return error; error = xfs_ialloc_pagi_init(mp, NULL, index); if (error) return error; pag = xfs_perag_get(mp, index); ifree += pag->pagi_freecount; ialloc += pag->pagi_count; bfree += pag->pagf_freeblks; bfreelst += pag->pagf_flcount; btree += pag->pagf_btreeblks; xfs_perag_put(pag); } /* Overwrite incore superblock counters with just-read data */ spin_lock(&mp->m_sb_lock); sbp->sb_ifree = ifree; sbp->sb_icount = ialloc; sbp->sb_fdblocks = bfree + bfreelst + btree; spin_unlock(&mp->m_sb_lock); xfs_reinit_percpu_counters(mp); return 0; } /* * xfs_log_sb() can be used to copy arbitrary changes to the in-core superblock * into the superblock buffer to be logged. It does not provide the higher * level of locking that is needed to protect the in-core superblock from * concurrent access. */ void xfs_log_sb( struct xfs_trans *tp) { struct xfs_mount *mp = tp->t_mountp; struct xfs_buf *bp = xfs_trans_getsb(tp, mp, 0); mp->m_sb.sb_icount = percpu_counter_sum(&mp->m_icount); mp->m_sb.sb_ifree = percpu_counter_sum(&mp->m_ifree); mp->m_sb.sb_fdblocks = percpu_counter_sum(&mp->m_fdblocks); xfs_sb_to_disk(XFS_BUF_TO_SBP(bp), &mp->m_sb); xfs_trans_buf_set_type(tp, bp, XFS_BLFT_SB_BUF); xfs_trans_log_buf(tp, bp, 0, sizeof(struct xfs_dsb)); } /* * xfs_sync_sb * * Sync the superblock to disk. * * Note that the caller is responsible for checking the frozen state of the * filesystem. This procedure uses the non-blocking transaction allocator and * thus will allow modifications to a frozen fs. This is required because this * code can be called during the process of freezing where use of the high-level * allocator would deadlock. */ int xfs_sync_sb( struct xfs_mount *mp, bool wait) { struct xfs_trans *tp; int error; tp = _xfs_trans_alloc(mp, XFS_TRANS_SB_CHANGE, KM_SLEEP); error = xfs_trans_reserve(tp, &M_RES(mp)->tr_sb, 0, 0); if (error) { xfs_trans_cancel(tp); return error; } xfs_log_sb(tp); if (wait) xfs_trans_set_sync(tp); return xfs_trans_commit(tp); } partclone-0.2.86/src/xfs/xfs_sb.h000066400000000000000000000030331262102574200166220ustar00rootroot00000000000000/* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __XFS_SB_H__ #define __XFS_SB_H__ /* * perag get/put wrappers for ref counting */ extern struct xfs_perag *xfs_perag_get(struct xfs_mount *, xfs_agnumber_t); extern struct xfs_perag *xfs_perag_get_tag(struct xfs_mount *, xfs_agnumber_t, int tag); extern void xfs_perag_put(struct xfs_perag *pag); extern int xfs_initialize_perag_data(struct xfs_mount *, xfs_agnumber_t); extern void xfs_sb_calc_crc(struct xfs_buf *bp); extern void xfs_log_sb(struct xfs_trans *tp); extern int xfs_sync_sb(struct xfs_mount *mp, bool wait); extern void xfs_sb_mount_common(struct xfs_mount *mp, struct xfs_sb *sbp); extern void xfs_sb_from_disk(struct xfs_sb *to, struct xfs_dsb *from); extern void xfs_sb_to_disk(struct xfs_dsb *to, struct xfs_sb *from); extern void xfs_sb_quota_from_disk(struct xfs_sb *sbp); #endif /* __XFS_SB_H__ */ partclone-0.2.86/src/xfs/xfs_shared.h000066400000000000000000000205061262102574200174700ustar00rootroot00000000000000/* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * Copyright (c) 2013 Red Hat, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __XFS_SHARED_H__ #define __XFS_SHARED_H__ /* * Definitions shared between kernel and userspace that don't fit into any other * header file that is shared with userspace. */ struct xfs_ifork; struct xfs_buf; struct xfs_buf_ops; struct xfs_mount; struct xfs_trans; struct xfs_inode; /* * Buffer verifier operations are widely used, including userspace tools */ extern const struct xfs_buf_ops xfs_agf_buf_ops; extern const struct xfs_buf_ops xfs_agi_buf_ops; extern const struct xfs_buf_ops xfs_agf_buf_ops; extern const struct xfs_buf_ops xfs_agfl_buf_ops; extern const struct xfs_buf_ops xfs_allocbt_buf_ops; extern const struct xfs_buf_ops xfs_attr3_leaf_buf_ops; extern const struct xfs_buf_ops xfs_attr3_rmt_buf_ops; extern const struct xfs_buf_ops xfs_bmbt_buf_ops; extern const struct xfs_buf_ops xfs_da3_node_buf_ops; extern const struct xfs_buf_ops xfs_dquot_buf_ops; extern const struct xfs_buf_ops xfs_symlink_buf_ops; extern const struct xfs_buf_ops xfs_agi_buf_ops; extern const struct xfs_buf_ops xfs_inobt_buf_ops; extern const struct xfs_buf_ops xfs_inode_buf_ops; extern const struct xfs_buf_ops xfs_inode_buf_ra_ops; extern const struct xfs_buf_ops xfs_dquot_buf_ops; extern const struct xfs_buf_ops xfs_sb_buf_ops; extern const struct xfs_buf_ops xfs_sb_quiet_buf_ops; extern const struct xfs_buf_ops xfs_symlink_buf_ops; /* * Transaction types. Used to distinguish types of buffers. These never reach * the log. */ #define XFS_TRANS_SETATTR_NOT_SIZE 1 #define XFS_TRANS_SETATTR_SIZE 2 #define XFS_TRANS_INACTIVE 3 #define XFS_TRANS_CREATE 4 #define XFS_TRANS_CREATE_TRUNC 5 #define XFS_TRANS_TRUNCATE_FILE 6 #define XFS_TRANS_REMOVE 7 #define XFS_TRANS_LINK 8 #define XFS_TRANS_RENAME 9 #define XFS_TRANS_MKDIR 10 #define XFS_TRANS_RMDIR 11 #define XFS_TRANS_SYMLINK 12 #define XFS_TRANS_SET_DMATTRS 13 #define XFS_TRANS_GROWFS 14 #define XFS_TRANS_STRAT_WRITE 15 #define XFS_TRANS_DIOSTRAT 16 /* 17 was XFS_TRANS_WRITE_SYNC */ #define XFS_TRANS_WRITEID 18 #define XFS_TRANS_ADDAFORK 19 #define XFS_TRANS_ATTRINVAL 20 #define XFS_TRANS_ATRUNCATE 21 #define XFS_TRANS_ATTR_SET 22 #define XFS_TRANS_ATTR_RM 23 #define XFS_TRANS_ATTR_FLAG 24 #define XFS_TRANS_CLEAR_AGI_BUCKET 25 #define XFS_TRANS_SB_CHANGE 26 /* * Dummy entries since we use the transaction type to index into the * trans_type[] in xlog_recover_print_trans_head() */ #define XFS_TRANS_DUMMY1 27 #define XFS_TRANS_DUMMY2 28 #define XFS_TRANS_QM_QUOTAOFF 29 #define XFS_TRANS_QM_DQALLOC 30 #define XFS_TRANS_QM_SETQLIM 31 #define XFS_TRANS_QM_DQCLUSTER 32 #define XFS_TRANS_QM_QINOCREATE 33 #define XFS_TRANS_QM_QUOTAOFF_END 34 #define XFS_TRANS_FSYNC_TS 35 #define XFS_TRANS_GROWFSRT_ALLOC 36 #define XFS_TRANS_GROWFSRT_ZERO 37 #define XFS_TRANS_GROWFSRT_FREE 38 #define XFS_TRANS_SWAPEXT 39 #define XFS_TRANS_CHECKPOINT 40 #define XFS_TRANS_ICREATE 41 #define XFS_TRANS_CREATE_TMPFILE 42 #define XFS_TRANS_TYPE_MAX 43 /* new transaction types need to be reflected in xfs_logprint(8) */ #define XFS_TRANS_TYPES \ { XFS_TRANS_SETATTR_NOT_SIZE, "SETATTR_NOT_SIZE" }, \ { XFS_TRANS_SETATTR_SIZE, "SETATTR_SIZE" }, \ { XFS_TRANS_INACTIVE, "INACTIVE" }, \ { XFS_TRANS_CREATE, "CREATE" }, \ { XFS_TRANS_CREATE_TRUNC, "CREATE_TRUNC" }, \ { XFS_TRANS_TRUNCATE_FILE, "TRUNCATE_FILE" }, \ { XFS_TRANS_REMOVE, "REMOVE" }, \ { XFS_TRANS_LINK, "LINK" }, \ { XFS_TRANS_RENAME, "RENAME" }, \ { XFS_TRANS_MKDIR, "MKDIR" }, \ { XFS_TRANS_RMDIR, "RMDIR" }, \ { XFS_TRANS_SYMLINK, "SYMLINK" }, \ { XFS_TRANS_SET_DMATTRS, "SET_DMATTRS" }, \ { XFS_TRANS_GROWFS, "GROWFS" }, \ { XFS_TRANS_STRAT_WRITE, "STRAT_WRITE" }, \ { XFS_TRANS_DIOSTRAT, "DIOSTRAT" }, \ { XFS_TRANS_WRITEID, "WRITEID" }, \ { XFS_TRANS_ADDAFORK, "ADDAFORK" }, \ { XFS_TRANS_ATTRINVAL, "ATTRINVAL" }, \ { XFS_TRANS_ATRUNCATE, "ATRUNCATE" }, \ { XFS_TRANS_ATTR_SET, "ATTR_SET" }, \ { XFS_TRANS_ATTR_RM, "ATTR_RM" }, \ { XFS_TRANS_ATTR_FLAG, "ATTR_FLAG" }, \ { XFS_TRANS_CLEAR_AGI_BUCKET, "CLEAR_AGI_BUCKET" }, \ { XFS_TRANS_SB_CHANGE, "SBCHANGE" }, \ { XFS_TRANS_DUMMY1, "DUMMY1" }, \ { XFS_TRANS_DUMMY2, "DUMMY2" }, \ { XFS_TRANS_QM_QUOTAOFF, "QM_QUOTAOFF" }, \ { XFS_TRANS_QM_DQALLOC, "QM_DQALLOC" }, \ { XFS_TRANS_QM_SETQLIM, "QM_SETQLIM" }, \ { XFS_TRANS_QM_DQCLUSTER, "QM_DQCLUSTER" }, \ { XFS_TRANS_QM_QINOCREATE, "QM_QINOCREATE" }, \ { XFS_TRANS_QM_QUOTAOFF_END, "QM_QOFF_END" }, \ { XFS_TRANS_FSYNC_TS, "FSYNC_TS" }, \ { XFS_TRANS_GROWFSRT_ALLOC, "GROWFSRT_ALLOC" }, \ { XFS_TRANS_GROWFSRT_ZERO, "GROWFSRT_ZERO" }, \ { XFS_TRANS_GROWFSRT_FREE, "GROWFSRT_FREE" }, \ { XFS_TRANS_SWAPEXT, "SWAPEXT" }, \ { XFS_TRANS_CHECKPOINT, "CHECKPOINT" }, \ { XFS_TRANS_ICREATE, "ICREATE" }, \ { XFS_TRANS_CREATE_TMPFILE, "CREATE_TMPFILE" }, \ { XLOG_UNMOUNT_REC_TYPE, "UNMOUNT" } /* * This structure is used to track log items associated with * a transaction. It points to the log item and keeps some * flags to track the state of the log item. It also tracks * the amount of space needed to log the item it describes * once we get to commit processing (see xfs_trans_commit()). */ struct xfs_log_item_desc { struct xfs_log_item *lid_item; struct list_head lid_trans; unsigned char lid_flags; }; #define XFS_LID_DIRTY 0x1 /* log size calculation functions */ int xfs_log_calc_unit_res(struct xfs_mount *mp, int unit_bytes); int xfs_log_calc_minimum_size(struct xfs_mount *); /* * Values for t_flags. */ #define XFS_TRANS_DIRTY 0x01 /* something needs to be logged */ #define XFS_TRANS_SB_DIRTY 0x02 /* superblock is modified */ #define XFS_TRANS_PERM_LOG_RES 0x04 /* xact took a permanent log res */ #define XFS_TRANS_SYNC 0x08 /* make commit synchronous */ #define XFS_TRANS_DQ_DIRTY 0x10 /* at least one dquot in trx dirty */ #define XFS_TRANS_RESERVE 0x20 /* OK to use reserved data blocks */ #define XFS_TRANS_FREEZE_PROT 0x40 /* Transaction has elevated writer count in superblock */ /* * Field values for xfs_trans_mod_sb. */ #define XFS_TRANS_SB_ICOUNT 0x00000001 #define XFS_TRANS_SB_IFREE 0x00000002 #define XFS_TRANS_SB_FDBLOCKS 0x00000004 #define XFS_TRANS_SB_RES_FDBLOCKS 0x00000008 #define XFS_TRANS_SB_FREXTENTS 0x00000010 #define XFS_TRANS_SB_RES_FREXTENTS 0x00000020 #define XFS_TRANS_SB_DBLOCKS 0x00000040 #define XFS_TRANS_SB_AGCOUNT 0x00000080 #define XFS_TRANS_SB_IMAXPCT 0x00000100 #define XFS_TRANS_SB_REXTSIZE 0x00000200 #define XFS_TRANS_SB_RBMBLOCKS 0x00000400 #define XFS_TRANS_SB_RBLOCKS 0x00000800 #define XFS_TRANS_SB_REXTENTS 0x00001000 #define XFS_TRANS_SB_REXTSLOG 0x00002000 /* * Here we centralize the specification of XFS meta-data buffer reference count * values. This determines how hard the buffer cache tries to hold onto the * buffer. */ #define XFS_AGF_REF 4 #define XFS_AGI_REF 4 #define XFS_AGFL_REF 3 #define XFS_INO_BTREE_REF 3 #define XFS_ALLOC_BTREE_REF 2 #define XFS_BMAP_BTREE_REF 2 #define XFS_DIR_BTREE_REF 2 #define XFS_INO_REF 2 #define XFS_ATTR_BTREE_REF 1 #define XFS_DQUOT_REF 1 /* * Flags for xfs_trans_ichgtime(). */ #define XFS_ICHGTIME_MOD 0x1 /* data fork modification timestamp */ #define XFS_ICHGTIME_CHG 0x2 /* inode field change timestamp */ #define XFS_ICHGTIME_CREATE 0x4 /* inode create timestamp */ /* * Symlink decoding/encoding functions */ int xfs_symlink_blocks(struct xfs_mount *mp, int pathlen); int xfs_symlink_hdr_set(struct xfs_mount *mp, xfs_ino_t ino, uint32_t offset, uint32_t size, struct xfs_buf *bp); bool xfs_symlink_hdr_ok(xfs_ino_t ino, uint32_t offset, uint32_t size, struct xfs_buf *bp); void xfs_symlink_local_to_remote(struct xfs_trans *tp, struct xfs_buf *bp, struct xfs_inode *ip, struct xfs_ifork *ifp); #endif /* __XFS_SHARED_H__ */ partclone-0.2.86/src/xfs/xfs_symlink_remote.c000066400000000000000000000113111262102574200212500ustar00rootroot00000000000000/* * Copyright (c) 2000-2006 Silicon Graphics, Inc. * Copyright (c) 2012-2013 Red Hat, Inc. * All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_shared.h" #include "xfs_trans_resv.h" #include "xfs_mount.h" #include "xfs_bmap_btree.h" #include "xfs_inode.h" #include "xfs_trace.h" #include "xfs_cksum.h" #include "xfs_trans.h" /* * Each contiguous block has a header, so it is not just a simple pathlen * to FSB conversion. */ int xfs_symlink_blocks( struct xfs_mount *mp, int pathlen) { int buflen = XFS_SYMLINK_BUF_SPACE(mp, mp->m_sb.sb_blocksize); return (pathlen + buflen - 1) / buflen; } int xfs_symlink_hdr_set( struct xfs_mount *mp, xfs_ino_t ino, uint32_t offset, uint32_t size, struct xfs_buf *bp) { struct xfs_dsymlink_hdr *dsl = bp->b_addr; if (!xfs_sb_version_hascrc(&mp->m_sb)) return 0; dsl->sl_magic = cpu_to_be32(XFS_SYMLINK_MAGIC); dsl->sl_offset = cpu_to_be32(offset); dsl->sl_bytes = cpu_to_be32(size); uuid_copy(&dsl->sl_uuid, &mp->m_sb.sb_meta_uuid); dsl->sl_owner = cpu_to_be64(ino); dsl->sl_blkno = cpu_to_be64(bp->b_bn); bp->b_ops = &xfs_symlink_buf_ops; return sizeof(struct xfs_dsymlink_hdr); } /* * Checking of the symlink header is split into two parts. the verifier does * CRC, location and bounds checking, the unpacking function checks the path * parameters and owner. */ bool xfs_symlink_hdr_ok( xfs_ino_t ino, uint32_t offset, uint32_t size, struct xfs_buf *bp) { struct xfs_dsymlink_hdr *dsl = bp->b_addr; if (offset != be32_to_cpu(dsl->sl_offset)) return false; if (size != be32_to_cpu(dsl->sl_bytes)) return false; if (ino != be64_to_cpu(dsl->sl_owner)) return false; /* ok */ return true; } static bool xfs_symlink_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_target->bt_mount; struct xfs_dsymlink_hdr *dsl = bp->b_addr; if (!xfs_sb_version_hascrc(&mp->m_sb)) return false; if (dsl->sl_magic != cpu_to_be32(XFS_SYMLINK_MAGIC)) return false; if (!uuid_equal(&dsl->sl_uuid, &mp->m_sb.sb_meta_uuid)) return false; if (bp->b_bn != be64_to_cpu(dsl->sl_blkno)) return false; if (be32_to_cpu(dsl->sl_offset) + be32_to_cpu(dsl->sl_bytes) >= MAXPATHLEN) return false; if (dsl->sl_owner == 0) return false; return true; } static void xfs_symlink_read_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_target->bt_mount; /* no verification of non-crc buffers */ if (!xfs_sb_version_hascrc(&mp->m_sb)) return; if (!xfs_buf_verify_cksum(bp, XFS_SYMLINK_CRC_OFF)) xfs_buf_ioerror(bp, -EFSBADCRC); else if (!xfs_symlink_verify(bp)) xfs_buf_ioerror(bp, -EFSCORRUPTED); if (bp->b_error) xfs_verifier_error(bp); } static void xfs_symlink_write_verify( struct xfs_buf *bp) { struct xfs_mount *mp = bp->b_target->bt_mount; struct xfs_buf_log_item *bip = bp->b_fspriv; /* no verification of non-crc buffers */ if (!xfs_sb_version_hascrc(&mp->m_sb)) return; if (!xfs_symlink_verify(bp)) { xfs_buf_ioerror(bp, -EFSCORRUPTED); xfs_verifier_error(bp); return; } if (bip) { struct xfs_dsymlink_hdr *dsl = bp->b_addr; dsl->sl_lsn = cpu_to_be64(bip->bli_item.li_lsn); } xfs_buf_update_cksum(bp, XFS_SYMLINK_CRC_OFF); } const struct xfs_buf_ops xfs_symlink_buf_ops = { .verify_read = xfs_symlink_read_verify, .verify_write = xfs_symlink_write_verify, }; void xfs_symlink_local_to_remote( struct xfs_trans *tp, struct xfs_buf *bp, struct xfs_inode *ip, struct xfs_ifork *ifp) { struct xfs_mount *mp = ip->i_mount; char *buf; xfs_trans_buf_set_type(tp, bp, XFS_BLFT_SYMLINK_BUF); if (!xfs_sb_version_hascrc(&mp->m_sb)) { bp->b_ops = NULL; memcpy(bp->b_addr, ifp->if_u1.if_data, ifp->if_bytes); return; } /* * As this symlink fits in an inode literal area, it must also fit in * the smallest buffer the filesystem supports. */ ASSERT(BBTOB(bp->b_length) >= ifp->if_bytes + sizeof(struct xfs_dsymlink_hdr)); bp->b_ops = &xfs_symlink_buf_ops; buf = bp->b_addr; buf += xfs_symlink_hdr_set(mp, ip->i_ino, 0, ifp->if_bytes, bp); memcpy(buf, ifp->if_u1.if_data, ifp->if_bytes); } partclone-0.2.86/src/xfs/xfs_trace.h000066400000000000000000000170471262102574200173260ustar00rootroot00000000000000/* * Copyright (c) 2011 RedHat, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __TRACE_H__ #define __TRACE_H__ #define trace_xfs_alloc_exact_done(a) ((void) 0) #define trace_xfs_alloc_exact_notfound(a) ((void) 0) #define trace_xfs_alloc_exact_error(a) ((void) 0) #define trace_xfs_alloc_near_nominleft(a) ((void) 0) #define trace_xfs_alloc_near_first(a) ((void) 0) #define trace_xfs_alloc_near_greater(a) ((void) 0) #define trace_xfs_alloc_near_lesser(a) ((void) 0) #define trace_xfs_alloc_near_error(a) ((void) 0) #define trace_xfs_alloc_near_noentry(a) ((void) 0) #define trace_xfs_alloc_near_busy(a) ((void) 0) #define trace_xfs_alloc_size_neither(a) ((void) 0) #define trace_xfs_alloc_size_noentry(a) ((void) 0) #define trace_xfs_alloc_size_nominleft(a) ((void) 0) #define trace_xfs_alloc_size_done(a) ((void) 0) #define trace_xfs_alloc_size_error(a) ((void) 0) #define trace_xfs_alloc_size_busy(a) ((void) 0) #define trace_xfs_alloc_small_freelist(a) ((void) 0) #define trace_xfs_alloc_small_notenough(a) ((void) 0) #define trace_xfs_alloc_small_done(a) ((void) 0) #define trace_xfs_alloc_small_error(a) ((void) 0) #define trace_xfs_alloc_vextent_badargs(a) ((void) 0) #define trace_xfs_alloc_vextent_nofix(a) ((void) 0) #define trace_xfs_alloc_vextent_noagbp(a) ((void) 0) #define trace_xfs_alloc_vextent_loopfailed(a) ((void) 0) #define trace_xfs_alloc_vextent_allfailed(a) ((void) 0) #define trace_xfs_log_recover_item_reorder_head(a,b,c,d) ((void) 0) #define trace_xfs_log_recover_item_reorder_tail(a,b,c,d) ((void) 0) #define trace_xfs_log_recover_item_add_cont(a,b,c,d) ((void) 0) #define trace_xfs_log_recover_item_add(a,b,c,d) ((void) 0) #define trace_xfs_btree_corrupt(a,b) ((void) 0) #define trace_xfs_da_btree_corrupt(a,b) ((void) 0) #define trace_xfs_free_extent(a,b,c,d,e,f,g) ((void) 0) #define trace_xfs_agf(a,b,c,d) ((void) 0) #define trace_xfs_read_agf(a,b) ((void) 0) #define trace_xfs_alloc_read_agf(a,b) ((void) 0) #define trace_xfs_read_agi(a,b) ((void) 0) #define trace_xfs_ialloc_read_agi(a,b) ((void) 0) #define trace_xfs_irec_merge_pre(a,b,c,d,e,f) ((void) 0) #define trace_xfs_irec_merge_post(a,b,c,d) ((void) 0) #define trace_xfs_iext_insert(a,b,c,d,e) ((void) 0) #define trace_xfs_iext_remove(a,b,c,d) ((void) 0) #define trace_xfs_dir2_grow_inode(a,b) ((void) 0) #define trace_xfs_dir2_shrink_inode(a,b) ((void) 0) #define trace_xfs_dir2_leaf_to_node(a) ((void) 0) #define trace_xfs_dir2_leaf_to_block(a) ((void) 0) #define trace_xfs_dir2_leaf_addname(a) ((void) 0) #define trace_xfs_dir2_leaf_lookup(a) ((void) 0) #define trace_xfs_dir2_leaf_removename(a) ((void) 0) #define trace_xfs_dir2_leaf_replace(a) ((void) 0) #define trace_xfs_dir2_block_addname(a) ((void) 0) #define trace_xfs_dir2_block_to_leaf(a) ((void) 0) #define trace_xfs_dir2_block_to_sf(a) ((void) 0) #define trace_xfs_dir2_block_lookup(a) ((void) 0) #define trace_xfs_dir2_block_removename(a) ((void) 0) #define trace_xfs_dir2_block_replace(a) ((void) 0) #define trace_xfs_dir2_leafn_add(a,b) ((void) 0) #define trace_xfs_dir2_leafn_remove(a,b) ((void) 0) #define trace_xfs_dir2_leafn_moveents(a,b,c,d) ((void) 0) #define trace_xfs_dir2_node_to_leaf(a) ((void) 0) #define trace_xfs_dir2_node_addname(a) ((void) 0) #define trace_xfs_dir2_node_lookup(a) ((void) 0) #define trace_xfs_dir2_node_removename(a) ((void) 0) #define trace_xfs_dir2_node_replace(a) ((void) 0) #define trace_xfs_dir2_sf_to_block(a) ((void) 0) #define trace_xfs_dir2_sf_addname(a) ((void) 0) #define trace_xfs_dir2_sf_create(a) ((void) 0) #define trace_xfs_dir2_sf_lookup(a) ((void) 0) #define trace_xfs_dir2_sf_removename(a) ((void) 0) #define trace_xfs_dir2_sf_replace(a) ((void) 0) #define trace_xfs_dir2_sf_toino4(a) ((void) 0) #define trace_xfs_dir2_sf_toino8(a) ((void) 0) #define trace_xfs_da_node_create(a) ((void) 0) #define trace_xfs_da_split(a) ((void) 0) #define trace_xfs_attr_leaf_split_before(a) ((void) 0) #define trace_xfs_attr_leaf_split_after(a) ((void) 0) #define trace_xfs_da_root_split(a) ((void) 0) #define trace_xfs_da_node_split(a) ((void) 0) #define trace_xfs_da_node_rebalance(a) ((void) 0) #define trace_xfs_da_node_add(a) ((void) 0) #define trace_xfs_da_join(a) ((void) 0) #define trace_xfs_da_root_join(a) ((void) 0) #define trace_xfs_da_node_toosmall(a) ((void) 0) #define trace_xfs_da_fixhashpath(a) ((void) 0) #define trace_xfs_da_node_remove(a) ((void) 0) #define trace_xfs_da_node_unbalance(a) ((void) 0) #define trace_xfs_da_link_before(a) ((void) 0) #define trace_xfs_da_link_after(a) ((void) 0) #define trace_xfs_da_unlink_back(a) ((void) 0) #define trace_xfs_da_unlink_forward(a) ((void) 0) #define trace_xfs_da_path_shift(a) ((void) 0) #define trace_xfs_da_grow_inode(a) ((void) 0) #define trace_xfs_da_swap_lastblock(a) ((void) 0) #define trace_xfs_da_shrink_inode(a) ((void) 0) #define trace_xfs_attr_sf_create(a) ((void) 0) #define trace_xfs_attr_sf_add(a) ((void) 0) #define trace_xfs_attr_sf_remove(a) ((void) 0) #define trace_xfs_attr_sf_lookup(a) ((void) 0) #define trace_xfs_attr_sf_to_leaf(a) ((void) 0) #define trace_xfs_attr_leaf_to_sf(a) ((void) 0) #define trace_xfs_attr_leaf_to_node(a) ((void) 0) #define trace_xfs_attr_leaf_create(a) ((void) 0) #define trace_xfs_attr_leaf_split(a) ((void) 0) #define trace_xfs_attr_leaf_add_old(a) ((void) 0) #define trace_xfs_attr_leaf_add_new(a) ((void) 0) #define trace_xfs_attr_leaf_add(a) ((void) 0) #define trace_xfs_attr_leaf_add_work(a) ((void) 0) #define trace_xfs_attr_leaf_compact(a) ((void) 0) #define trace_xfs_attr_leaf_rebalance(a) ((void) 0) #define trace_xfs_attr_leaf_toosmall(a) ((void) 0) #define trace_xfs_attr_leaf_remove(a) ((void) 0) #define trace_xfs_attr_leaf_unbalance(a) ((void) 0) #define trace_xfs_attr_leaf_lookup(a) ((void) 0) #define trace_xfs_attr_leaf_clearflag(a) ((void) 0) #define trace_xfs_attr_leaf_setflag(a) ((void) 0) #define trace_xfs_attr_leaf_flipflags(a) ((void) 0) #define trace_xfs_attr_sf_addname(a) ((void) 0) #define trace_xfs_attr_leaf_addname(a) ((void) 0) #define trace_xfs_attr_leaf_replace(a) ((void) 0) #define trace_xfs_attr_leaf_removename(a) ((void) 0) #define trace_xfs_attr_leaf_get(a) ((void) 0) #define trace_xfs_attr_node_addname(a) ((void) 0) #define trace_xfs_attr_node_replace(a) ((void) 0) #define trace_xfs_attr_node_removename(a) ((void) 0) #define trace_xfs_attr_fillstate(a) ((void) 0) #define trace_xfs_attr_refillstate(a) ((void) 0) #define trace_xfs_attr_node_get(a) ((void) 0) #define trace_xfs_attr_rmtval_get(a) ((void) 0) #define trace_xfs_attr_rmtval_set(a) ((void) 0) #define trace_xfs_attr_rmtval_remove(a) ((void) 0) #define trace_xfs_bmap_pre_update(a,b,c,d) ((void) 0) #define trace_xfs_bmap_post_update(a,b,c,d) ((void) 0) #define trace_xfs_extlist(a,b,c,d) ((void) 0) #define trace_xfs_bunmap(a,b,c,d,e) ((void) 0) /* set c = c to avoid unused var warnings */ #define trace_xfs_perag_get(a,b,c,d) ((c) = (c)) #define trace_xfs_perag_get_tag(a,b,c,d) ((c) = (c)) #define trace_xfs_perag_put(a,b,c,d) ((c) = (c)) #endif /* __TRACE_H__ */ partclone-0.2.86/src/xfs/xfs_trans.h000066400000000000000000000117711262102574200173550ustar00rootroot00000000000000/* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __XFS_TRANS_H__ #define __XFS_TRANS_H__ struct xfs_mount; struct xfs_buftarg; struct xfs_buf; struct xfs_buf_map; /* * Userspace Transaction interface */ typedef struct xfs_log_item { struct xfs_log_item_desc *li_desc; /* ptr to current desc*/ struct xfs_mount *li_mountp; /* ptr to fs mount */ uint li_type; /* item type */ xfs_lsn_t li_lsn; } xfs_log_item_t; typedef struct xfs_inode_log_item { xfs_log_item_t ili_item; /* common portion */ struct xfs_inode *ili_inode; /* inode pointer */ unsigned short ili_flags; /* misc flags */ unsigned int ili_fields; /* fields to be logged */ unsigned int ili_last_fields; /* fields when flushed*/ xfs_inode_log_format_t ili_format; /* logged structure */ } xfs_inode_log_item_t; typedef struct xfs_buf_log_item { xfs_log_item_t bli_item; /* common item structure */ struct xfs_buf *bli_buf; /* real buffer pointer */ unsigned int bli_flags; /* misc flags */ unsigned int bli_recur; /* recursion count */ xfs_buf_log_format_t bli_format; /* in-log header */ } xfs_buf_log_item_t; #define XFS_BLI_DIRTY (1<<0) #define XFS_BLI_HOLD (1<<1) #define XFS_BLI_STALE (1<<2) #define XFS_BLI_INODE_ALLOC_BUF (1<<3) typedef struct xfs_dq_logitem { xfs_log_item_t qli_item; /* common portion */ struct xfs_dquot *qli_dquot; /* dquot ptr */ xfs_lsn_t qli_flush_lsn; /* lsn at last flush */ xfs_dq_logformat_t qli_format; /* logged structure */ } xfs_dq_logitem_t; typedef struct xfs_qoff_logitem { xfs_log_item_t qql_item; /* common portion */ struct xfs_qoff_logitem *qql_start_lip; /* qoff-start logitem, if any */ xfs_qoff_logformat_t qql_format; /* logged structure */ } xfs_qoff_logitem_t; typedef struct xfs_trans { unsigned int t_type; /* transaction type */ unsigned int t_log_res; /* amt of log space resvd */ unsigned int t_log_count; /* count for perm log res */ struct xfs_mount *t_mountp; /* ptr to fs mount struct */ unsigned int t_flags; /* misc flags */ long t_icount_delta; /* superblock icount change */ long t_ifree_delta; /* superblock ifree change */ long t_fdblocks_delta; /* superblock fdblocks chg */ long t_frextents_delta; /* superblock freextents chg */ struct list_head t_items; /* first log item desc chunk */ } xfs_trans_t; void xfs_trans_init(struct xfs_mount *); int xfs_trans_roll(struct xfs_trans **, struct xfs_inode *); xfs_trans_t *libxfs_trans_alloc(struct xfs_mount *, int); int libxfs_trans_reserve(struct xfs_trans *, struct xfs_trans_res *, uint, uint); int libxfs_trans_commit(struct xfs_trans *); void libxfs_trans_cancel(struct xfs_trans *); struct xfs_buf *libxfs_trans_getsb(struct xfs_trans *, struct xfs_mount *, int); int libxfs_trans_iget(struct xfs_mount *, struct xfs_trans *, xfs_ino_t, uint, uint, struct xfs_inode **); void libxfs_trans_ijoin(struct xfs_trans *, struct xfs_inode *, uint); void libxfs_trans_ijoin_ref(struct xfs_trans *, struct xfs_inode *, int); void libxfs_trans_log_inode (struct xfs_trans *, struct xfs_inode *, uint); void libxfs_trans_brelse(struct xfs_trans *, struct xfs_buf *); void libxfs_trans_binval(struct xfs_trans *, struct xfs_buf *); void libxfs_trans_bjoin(struct xfs_trans *, struct xfs_buf *); void libxfs_trans_bhold(struct xfs_trans *, struct xfs_buf *); void libxfs_trans_log_buf(struct xfs_trans *, struct xfs_buf *, uint, uint); struct xfs_buf *libxfs_trans_get_buf_map(struct xfs_trans *tp, struct xfs_buftarg *btp, struct xfs_buf_map *map, int nmaps, uint flags); int libxfs_trans_read_buf_map(struct xfs_mount *mp, struct xfs_trans *tp, struct xfs_buftarg *btp, struct xfs_buf_map *map, int nmaps, uint flags, struct xfs_buf **bpp, const struct xfs_buf_ops *ops); static inline struct xfs_buf * libxfs_trans_get_buf( struct xfs_trans *tp, struct xfs_buftarg *btp, xfs_daddr_t blkno, int numblks, uint flags) { DEFINE_SINGLE_BUF_MAP(map, blkno, numblks); return libxfs_trans_get_buf_map(tp, btp, &map, 1, flags); } static inline int libxfs_trans_read_buf( struct xfs_mount *mp, struct xfs_trans *tp, struct xfs_buftarg *btp, xfs_daddr_t blkno, int numblks, uint flags, struct xfs_buf **bpp, const struct xfs_buf_ops *ops) { DEFINE_SINGLE_BUF_MAP(map, blkno, numblks); return libxfs_trans_read_buf_map(mp, tp, btp, &map, 1, flags, bpp, ops); } #endif /* __XFS_TRANS_H__ */ partclone-0.2.86/src/xfs/xfs_trans_resv.c000066400000000000000000000703741262102574200204130ustar00rootroot00000000000000/* * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. * Copyright (C) 2010 Red Hat, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "libxfs_priv.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_mount.h" #include "xfs_da_format.h" #include "xfs_da_btree.h" #include "xfs_inode.h" #include "xfs_bmap_btree.h" #include "xfs_ialloc.h" #include "xfs_trans.h" #include "xfs_trans_space.h" #include "xfs_trace.h" #include "xfs_quota_defs.h" /* * A buffer has a format structure overhead in the log in addition * to the data, so we need to take this into account when reserving * space in a transaction for a buffer. Round the space required up * to a multiple of 128 bytes so that we don't change the historical * reservation that has been used for this overhead. */ STATIC uint xfs_buf_log_overhead(void) { return round_up(sizeof(struct xlog_op_header) + sizeof(struct xfs_buf_log_format), 128); } /* * Calculate out transaction log reservation per item in bytes. * * The nbufs argument is used to indicate the number of items that * will be changed in a transaction. size is used to tell how many * bytes should be reserved per item. */ STATIC uint xfs_calc_buf_res( uint nbufs, uint size) { return nbufs * (size + xfs_buf_log_overhead()); } /* * Logging inodes is really tricksy. They are logged in memory format, * which means that what we write into the log doesn't directly translate into * the amount of space they use on disk. * * Case in point - btree format forks in memory format use more space than the * on-disk format. In memory, the buffer contains a normal btree block header so * the btree code can treat it as though it is just another generic buffer. * However, when we write it to the inode fork, we don't write all of this * header as it isn't needed. e.g. the root is only ever in the inode, so * there's no need for sibling pointers which would waste 16 bytes of space. * * Hence when we have an inode with a maximally sized btree format fork, then * amount of information we actually log is greater than the size of the inode * on disk. Hence we need an inode reservation function that calculates all this * correctly. So, we log: * * - 4 log op headers for object * - for the ilf, the inode core and 2 forks * - inode log format object * - the inode core * - two inode forks containing bmap btree root blocks. * - the btree data contained by both forks will fit into the inode size, * hence when combined with the inode core above, we have a total of the * actual inode size. * - the BMBT headers need to be accounted separately, as they are * additional to the records and pointers that fit inside the inode * forks. */ STATIC uint xfs_calc_inode_res( struct xfs_mount *mp, uint ninodes) { return ninodes * (4 * sizeof(struct xlog_op_header) + sizeof(struct xfs_inode_log_format) + mp->m_sb.sb_inodesize + 2 * XFS_BMBT_BLOCK_LEN(mp)); } /* * The free inode btree is a conditional feature and the log reservation * requirements differ slightly from that of the traditional inode allocation * btree. The finobt tracks records for inode chunks with at least one free * inode. A record can be removed from the tree for an inode allocation * or free and thus the finobt reservation is unconditional across: * * - inode allocation * - inode free * - inode chunk allocation * * The 'modify' param indicates to include the record modification scenario. The * 'alloc' param indicates to include the reservation for free space btree * modifications on behalf of finobt modifications. This is required only for * transactions that do not already account for free space btree modifications. * * the free inode btree: max depth * block size * the allocation btrees: 2 trees * (max depth - 1) * block size * the free inode btree entry: block size */ STATIC uint xfs_calc_finobt_res( struct xfs_mount *mp, int alloc, int modify) { uint res; if (!xfs_sb_version_hasfinobt(&mp->m_sb)) return 0; res = xfs_calc_buf_res(mp->m_in_maxlevels, XFS_FSB_TO_B(mp, 1)); if (alloc) res += xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1), XFS_FSB_TO_B(mp, 1)); if (modify) res += (uint)XFS_FSB_TO_B(mp, 1); return res; } /* * Various log reservation values. * * These are based on the size of the file system block because that is what * most transactions manipulate. Each adds in an additional 128 bytes per * item logged to try to account for the overhead of the transaction mechanism. * * Note: Most of the reservations underestimate the number of allocation * groups into which they could free extents in the xfs_bmap_finish() call. * This is because the number in the worst case is quite high and quite * unusual. In order to fix this we need to change xfs_bmap_finish() to free * extents in only a single AG at a time. This will require changes to the * EFI code as well, however, so that the EFI for the extents not freed is * logged again in each transaction. See SGI PV #261917. * * Reservation functions here avoid a huge stack in xfs_trans_init due to * register overflow from temporaries in the calculations. */ /* * In a write transaction we can allocate a maximum of 2 * extents. This gives: * the inode getting the new extents: inode size * the inode's bmap btree: max depth * block size * the agfs of the ags from which the extents are allocated: 2 * sector * the superblock free block counter: sector size * the allocation btrees: 2 exts * 2 trees * (2 * max depth - 1) * block size * And the bmap_finish transaction can free bmap blocks in a join: * the agfs of the ags containing the blocks: 2 * sector size * the agfls of the ags containing the blocks: 2 * sector size * the super block free block counter: sector size * the allocation btrees: 2 exts * 2 trees * (2 * max depth - 1) * block size */ STATIC uint xfs_calc_write_reservation( struct xfs_mount *mp) { return XFS_DQUOT_LOGRES(mp) + MAX((xfs_calc_inode_res(mp, 1) + xfs_calc_buf_res(XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK), XFS_FSB_TO_B(mp, 1)) + xfs_calc_buf_res(3, mp->m_sb.sb_sectsize) + xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 2), XFS_FSB_TO_B(mp, 1))), (xfs_calc_buf_res(5, mp->m_sb.sb_sectsize) + xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 2), XFS_FSB_TO_B(mp, 1)))); } /* * In truncating a file we free up to two extents at once. We can modify: * the inode being truncated: inode size * the inode's bmap btree: (max depth + 1) * block size * And the bmap_finish transaction can free the blocks and bmap blocks: * the agf for each of the ags: 4 * sector size * the agfl for each of the ags: 4 * sector size * the super block to reflect the freed blocks: sector size * worst case split in allocation btrees per extent assuming 4 extents: * 4 exts * 2 trees * (2 * max depth - 1) * block size * the inode btree: max depth * blocksize * the allocation btrees: 2 trees * (max depth - 1) * block size */ STATIC uint xfs_calc_itruncate_reservation( struct xfs_mount *mp) { return XFS_DQUOT_LOGRES(mp) + MAX((xfs_calc_inode_res(mp, 1) + xfs_calc_buf_res(XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) + 1, XFS_FSB_TO_B(mp, 1))), (xfs_calc_buf_res(9, mp->m_sb.sb_sectsize) + xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 4), XFS_FSB_TO_B(mp, 1)) + xfs_calc_buf_res(5, 0) + xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1), XFS_FSB_TO_B(mp, 1)) + xfs_calc_buf_res(2 + mp->m_ialloc_blks + mp->m_in_maxlevels, 0))); } /* * In renaming a files we can modify: * the four inodes involved: 4 * inode size * the two directory btrees: 2 * (max depth + v2) * dir block size * the two directory bmap btrees: 2 * max depth * block size * And the bmap_finish transaction can free dir and bmap blocks (two sets * of bmap blocks) giving: * the agf for the ags in which the blocks live: 3 * sector size * the agfl for the ags in which the blocks live: 3 * sector size * the superblock for the free block count: sector size * the allocation btrees: 3 exts * 2 trees * (2 * max depth - 1) * block size */ STATIC uint xfs_calc_rename_reservation( struct xfs_mount *mp) { return XFS_DQUOT_LOGRES(mp) + MAX((xfs_calc_inode_res(mp, 4) + xfs_calc_buf_res(2 * XFS_DIROP_LOG_COUNT(mp), XFS_FSB_TO_B(mp, 1))), (xfs_calc_buf_res(7, mp->m_sb.sb_sectsize) + xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 3), XFS_FSB_TO_B(mp, 1)))); } /* * For removing an inode from unlinked list at first, we can modify: * the agi hash list and counters: sector size * the on disk inode before ours in the agi hash list: inode cluster size */ STATIC uint xfs_calc_iunlink_remove_reservation( struct xfs_mount *mp) { return xfs_calc_buf_res(1, mp->m_sb.sb_sectsize) + max_t(uint, XFS_FSB_TO_B(mp, 1), mp->m_inode_cluster_size); } /* * For creating a link to an inode: * the parent directory inode: inode size * the linked inode: inode size * the directory btree could split: (max depth + v2) * dir block size * the directory bmap btree could join or split: (max depth + v2) * blocksize * And the bmap_finish transaction can free some bmap blocks giving: * the agf for the ag in which the blocks live: sector size * the agfl for the ag in which the blocks live: sector size * the superblock for the free block count: sector size * the allocation btrees: 2 trees * (2 * max depth - 1) * block size */ STATIC uint xfs_calc_link_reservation( struct xfs_mount *mp) { return XFS_DQUOT_LOGRES(mp) + xfs_calc_iunlink_remove_reservation(mp) + MAX((xfs_calc_inode_res(mp, 2) + xfs_calc_buf_res(XFS_DIROP_LOG_COUNT(mp), XFS_FSB_TO_B(mp, 1))), (xfs_calc_buf_res(3, mp->m_sb.sb_sectsize) + xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1), XFS_FSB_TO_B(mp, 1)))); } /* * For adding an inode to unlinked list we can modify: * the agi hash list: sector size * the unlinked inode: inode size */ STATIC uint xfs_calc_iunlink_add_reservation(xfs_mount_t *mp) { return xfs_calc_buf_res(1, mp->m_sb.sb_sectsize) + xfs_calc_inode_res(mp, 1); } /* * For removing a directory entry we can modify: * the parent directory inode: inode size * the removed inode: inode size * the directory btree could join: (max depth + v2) * dir block size * the directory bmap btree could join or split: (max depth + v2) * blocksize * And the bmap_finish transaction can free the dir and bmap blocks giving: * the agf for the ag in which the blocks live: 2 * sector size * the agfl for the ag in which the blocks live: 2 * sector size * the superblock for the free block count: sector size * the allocation btrees: 2 exts * 2 trees * (2 * max depth - 1) * block size */ STATIC uint xfs_calc_remove_reservation( struct xfs_mount *mp) { return XFS_DQUOT_LOGRES(mp) + xfs_calc_iunlink_add_reservation(mp) + MAX((xfs_calc_inode_res(mp, 1) + xfs_calc_buf_res(XFS_DIROP_LOG_COUNT(mp), XFS_FSB_TO_B(mp, 1))), (xfs_calc_buf_res(4, mp->m_sb.sb_sectsize) + xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 2), XFS_FSB_TO_B(mp, 1)))); } /* * For create, break it in to the two cases that the transaction * covers. We start with the modify case - allocation done by modification * of the state of existing inodes - and the allocation case. */ /* * For create we can modify: * the parent directory inode: inode size * the new inode: inode size * the inode btree entry: block size * the superblock for the nlink flag: sector size * the directory btree: (max depth + v2) * dir block size * the directory inode's bmap btree: (max depth + v2) * block size * the finobt (record modification and allocation btrees) */ STATIC uint xfs_calc_create_resv_modify( struct xfs_mount *mp) { return xfs_calc_inode_res(mp, 2) + xfs_calc_buf_res(1, mp->m_sb.sb_sectsize) + (uint)XFS_FSB_TO_B(mp, 1) + xfs_calc_buf_res(XFS_DIROP_LOG_COUNT(mp), XFS_FSB_TO_B(mp, 1)) + xfs_calc_finobt_res(mp, 1, 1); } /* * For create we can allocate some inodes giving: * the agi and agf of the ag getting the new inodes: 2 * sectorsize * the superblock for the nlink flag: sector size * the inode blocks allocated: mp->m_ialloc_blks * blocksize * the inode btree: max depth * blocksize * the allocation btrees: 2 trees * (max depth - 1) * block size */ STATIC uint xfs_calc_create_resv_alloc( struct xfs_mount *mp) { return xfs_calc_buf_res(2, mp->m_sb.sb_sectsize) + mp->m_sb.sb_sectsize + xfs_calc_buf_res(mp->m_ialloc_blks, XFS_FSB_TO_B(mp, 1)) + xfs_calc_buf_res(mp->m_in_maxlevels, XFS_FSB_TO_B(mp, 1)) + xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1), XFS_FSB_TO_B(mp, 1)); } STATIC uint __xfs_calc_create_reservation( struct xfs_mount *mp) { return XFS_DQUOT_LOGRES(mp) + MAX(xfs_calc_create_resv_alloc(mp), xfs_calc_create_resv_modify(mp)); } /* * For icreate we can allocate some inodes giving: * the agi and agf of the ag getting the new inodes: 2 * sectorsize * the superblock for the nlink flag: sector size * the inode btree: max depth * blocksize * the allocation btrees: 2 trees * (max depth - 1) * block size * the finobt (record insertion) */ STATIC uint xfs_calc_icreate_resv_alloc( struct xfs_mount *mp) { return xfs_calc_buf_res(2, mp->m_sb.sb_sectsize) + mp->m_sb.sb_sectsize + xfs_calc_buf_res(mp->m_in_maxlevels, XFS_FSB_TO_B(mp, 1)) + xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1), XFS_FSB_TO_B(mp, 1)) + xfs_calc_finobt_res(mp, 0, 0); } STATIC uint xfs_calc_icreate_reservation(xfs_mount_t *mp) { return XFS_DQUOT_LOGRES(mp) + MAX(xfs_calc_icreate_resv_alloc(mp), xfs_calc_create_resv_modify(mp)); } STATIC uint xfs_calc_create_reservation( struct xfs_mount *mp) { if (xfs_sb_version_hascrc(&mp->m_sb)) return xfs_calc_icreate_reservation(mp); return __xfs_calc_create_reservation(mp); } STATIC uint xfs_calc_create_tmpfile_reservation( struct xfs_mount *mp) { uint res = XFS_DQUOT_LOGRES(mp); if (xfs_sb_version_hascrc(&mp->m_sb)) res += xfs_calc_icreate_resv_alloc(mp); else res += xfs_calc_create_resv_alloc(mp); return res + xfs_calc_iunlink_add_reservation(mp); } /* * Making a new directory is the same as creating a new file. */ STATIC uint xfs_calc_mkdir_reservation( struct xfs_mount *mp) { return xfs_calc_create_reservation(mp); } /* * Making a new symplink is the same as creating a new file, but * with the added blocks for remote symlink data which can be up to 1kB in * length (MAXPATHLEN). */ STATIC uint xfs_calc_symlink_reservation( struct xfs_mount *mp) { return xfs_calc_create_reservation(mp) + xfs_calc_buf_res(1, MAXPATHLEN); } /* * In freeing an inode we can modify: * the inode being freed: inode size * the super block free inode counter: sector size * the agi hash list and counters: sector size * the inode btree entry: block size * the on disk inode before ours in the agi hash list: inode cluster size * the inode btree: max depth * blocksize * the allocation btrees: 2 trees * (max depth - 1) * block size * the finobt (record insertion, removal or modification) */ STATIC uint xfs_calc_ifree_reservation( struct xfs_mount *mp) { return XFS_DQUOT_LOGRES(mp) + xfs_calc_inode_res(mp, 1) + xfs_calc_buf_res(1, mp->m_sb.sb_sectsize) + xfs_calc_buf_res(1, XFS_FSB_TO_B(mp, 1)) + xfs_calc_iunlink_remove_reservation(mp) + xfs_calc_buf_res(1, 0) + xfs_calc_buf_res(2 + mp->m_ialloc_blks + mp->m_in_maxlevels, 0) + xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1), XFS_FSB_TO_B(mp, 1)) + xfs_calc_finobt_res(mp, 0, 1); } /* * When only changing the inode we log the inode and possibly the superblock * We also add a bit of slop for the transaction stuff. */ STATIC uint xfs_calc_ichange_reservation( struct xfs_mount *mp) { return XFS_DQUOT_LOGRES(mp) + xfs_calc_inode_res(mp, 1) + xfs_calc_buf_res(1, mp->m_sb.sb_sectsize); } /* * Growing the data section of the filesystem. * superblock * agi and agf * allocation btrees */ STATIC uint xfs_calc_growdata_reservation( struct xfs_mount *mp) { return xfs_calc_buf_res(3, mp->m_sb.sb_sectsize) + xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1), XFS_FSB_TO_B(mp, 1)); } /* * Growing the rt section of the filesystem. * In the first set of transactions (ALLOC) we allocate space to the * bitmap or summary files. * superblock: sector size * agf of the ag from which the extent is allocated: sector size * bmap btree for bitmap/summary inode: max depth * blocksize * bitmap/summary inode: inode size * allocation btrees for 1 block alloc: 2 * (2 * maxdepth - 1) * blocksize */ STATIC uint xfs_calc_growrtalloc_reservation( struct xfs_mount *mp) { return xfs_calc_buf_res(2, mp->m_sb.sb_sectsize) + xfs_calc_buf_res(XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK), XFS_FSB_TO_B(mp, 1)) + xfs_calc_inode_res(mp, 1) + xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1), XFS_FSB_TO_B(mp, 1)); } /* * Growing the rt section of the filesystem. * In the second set of transactions (ZERO) we zero the new metadata blocks. * one bitmap/summary block: blocksize */ STATIC uint xfs_calc_growrtzero_reservation( struct xfs_mount *mp) { return xfs_calc_buf_res(1, mp->m_sb.sb_blocksize); } /* * Growing the rt section of the filesystem. * In the third set of transactions (FREE) we update metadata without * allocating any new blocks. * superblock: sector size * bitmap inode: inode size * summary inode: inode size * one bitmap block: blocksize * summary blocks: new summary size */ STATIC uint xfs_calc_growrtfree_reservation( struct xfs_mount *mp) { return xfs_calc_buf_res(1, mp->m_sb.sb_sectsize) + xfs_calc_inode_res(mp, 2) + xfs_calc_buf_res(1, mp->m_sb.sb_blocksize) + xfs_calc_buf_res(1, mp->m_rsumsize); } /* * Logging the inode modification timestamp on a synchronous write. * inode */ STATIC uint xfs_calc_swrite_reservation( struct xfs_mount *mp) { return xfs_calc_inode_res(mp, 1); } /* * Logging the inode mode bits when writing a setuid/setgid file * inode */ STATIC uint xfs_calc_writeid_reservation( struct xfs_mount *mp) { return xfs_calc_inode_res(mp, 1); } /* * Converting the inode from non-attributed to attributed. * the inode being converted: inode size * agf block and superblock (for block allocation) * the new block (directory sized) * bmap blocks for the new directory block * allocation btrees */ STATIC uint xfs_calc_addafork_reservation( struct xfs_mount *mp) { return XFS_DQUOT_LOGRES(mp) + xfs_calc_inode_res(mp, 1) + xfs_calc_buf_res(2, mp->m_sb.sb_sectsize) + xfs_calc_buf_res(1, mp->m_dir_geo->blksize) + xfs_calc_buf_res(XFS_DAENTER_BMAP1B(mp, XFS_DATA_FORK) + 1, XFS_FSB_TO_B(mp, 1)) + xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1), XFS_FSB_TO_B(mp, 1)); } /* * Removing the attribute fork of a file * the inode being truncated: inode size * the inode's bmap btree: max depth * block size * And the bmap_finish transaction can free the blocks and bmap blocks: * the agf for each of the ags: 4 * sector size * the agfl for each of the ags: 4 * sector size * the super block to reflect the freed blocks: sector size * worst case split in allocation btrees per extent assuming 4 extents: * 4 exts * 2 trees * (2 * max depth - 1) * block size */ STATIC uint xfs_calc_attrinval_reservation( struct xfs_mount *mp) { return MAX((xfs_calc_inode_res(mp, 1) + xfs_calc_buf_res(XFS_BM_MAXLEVELS(mp, XFS_ATTR_FORK), XFS_FSB_TO_B(mp, 1))), (xfs_calc_buf_res(9, mp->m_sb.sb_sectsize) + xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 4), XFS_FSB_TO_B(mp, 1)))); } /* * Setting an attribute at mount time. * the inode getting the attribute * the superblock for allocations * the agfs extents are allocated from * the attribute btree * max depth * the inode allocation btree * Since attribute transaction space is dependent on the size of the attribute, * the calculation is done partially at mount time and partially at runtime(see * below). */ STATIC uint xfs_calc_attrsetm_reservation( struct xfs_mount *mp) { return XFS_DQUOT_LOGRES(mp) + xfs_calc_inode_res(mp, 1) + xfs_calc_buf_res(1, mp->m_sb.sb_sectsize) + xfs_calc_buf_res(XFS_DA_NODE_MAXDEPTH, XFS_FSB_TO_B(mp, 1)); } /* * Setting an attribute at runtime, transaction space unit per block. * the superblock for allocations: sector size * the inode bmap btree could join or split: max depth * block size * Since the runtime attribute transaction space is dependent on the total * blocks needed for the 1st bmap, here we calculate out the space unit for * one block so that the caller could figure out the total space according * to the attibute extent length in blocks by: * ext * M_RES(mp)->tr_attrsetrt.tr_logres */ STATIC uint xfs_calc_attrsetrt_reservation( struct xfs_mount *mp) { return xfs_calc_buf_res(1, mp->m_sb.sb_sectsize) + xfs_calc_buf_res(XFS_BM_MAXLEVELS(mp, XFS_ATTR_FORK), XFS_FSB_TO_B(mp, 1)); } /* * Removing an attribute. * the inode: inode size * the attribute btree could join: max depth * block size * the inode bmap btree could join or split: max depth * block size * And the bmap_finish transaction can free the attr blocks freed giving: * the agf for the ag in which the blocks live: 2 * sector size * the agfl for the ag in which the blocks live: 2 * sector size * the superblock for the free block count: sector size * the allocation btrees: 2 exts * 2 trees * (2 * max depth - 1) * block size */ STATIC uint xfs_calc_attrrm_reservation( struct xfs_mount *mp) { return XFS_DQUOT_LOGRES(mp) + MAX((xfs_calc_inode_res(mp, 1) + xfs_calc_buf_res(XFS_DA_NODE_MAXDEPTH, XFS_FSB_TO_B(mp, 1)) + (uint)XFS_FSB_TO_B(mp, XFS_BM_MAXLEVELS(mp, XFS_ATTR_FORK)) + xfs_calc_buf_res(XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK), 0)), (xfs_calc_buf_res(5, mp->m_sb.sb_sectsize) + xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 2), XFS_FSB_TO_B(mp, 1)))); } /* * Clearing a bad agino number in an agi hash bucket. */ STATIC uint xfs_calc_clear_agi_bucket_reservation( struct xfs_mount *mp) { return xfs_calc_buf_res(1, mp->m_sb.sb_sectsize); } /* * Adjusting quota limits. * the xfs_disk_dquot_t: sizeof(struct xfs_disk_dquot) */ STATIC uint xfs_calc_qm_setqlim_reservation( struct xfs_mount *mp) { return xfs_calc_buf_res(1, sizeof(struct xfs_disk_dquot)); } /* * Allocating quota on disk if needed. * the write transaction log space for quota file extent allocation * the unit of quota allocation: one system block size */ STATIC uint xfs_calc_qm_dqalloc_reservation( struct xfs_mount *mp) { return xfs_calc_write_reservation(mp) + xfs_calc_buf_res(1, XFS_FSB_TO_B(mp, XFS_DQUOT_CLUSTER_SIZE_FSB) - 1); } /* * Turning off quotas. * the xfs_qoff_logitem_t: sizeof(struct xfs_qoff_logitem) * 2 * the superblock for the quota flags: sector size */ STATIC uint xfs_calc_qm_quotaoff_reservation( struct xfs_mount *mp) { return sizeof(struct xfs_qoff_logitem) * 2 + xfs_calc_buf_res(1, mp->m_sb.sb_sectsize); } /* * End of turning off quotas. * the xfs_qoff_logitem_t: sizeof(struct xfs_qoff_logitem) * 2 */ STATIC uint xfs_calc_qm_quotaoff_end_reservation( struct xfs_mount *mp) { return sizeof(struct xfs_qoff_logitem) * 2; } /* * Syncing the incore super block changes to disk. * the super block to reflect the changes: sector size */ STATIC uint xfs_calc_sb_reservation( struct xfs_mount *mp) { return xfs_calc_buf_res(1, mp->m_sb.sb_sectsize); } void xfs_trans_resv_calc( struct xfs_mount *mp, struct xfs_trans_resv *resp) { /* * The following transactions are logged in physical format and * require a permanent reservation on space. */ resp->tr_write.tr_logres = xfs_calc_write_reservation(mp); resp->tr_write.tr_logcount = XFS_WRITE_LOG_COUNT; resp->tr_write.tr_logflags |= XFS_TRANS_PERM_LOG_RES; resp->tr_itruncate.tr_logres = xfs_calc_itruncate_reservation(mp); resp->tr_itruncate.tr_logcount = XFS_ITRUNCATE_LOG_COUNT; resp->tr_itruncate.tr_logflags |= XFS_TRANS_PERM_LOG_RES; resp->tr_rename.tr_logres = xfs_calc_rename_reservation(mp); resp->tr_rename.tr_logcount = XFS_RENAME_LOG_COUNT; resp->tr_rename.tr_logflags |= XFS_TRANS_PERM_LOG_RES; resp->tr_link.tr_logres = xfs_calc_link_reservation(mp); resp->tr_link.tr_logcount = XFS_LINK_LOG_COUNT; resp->tr_link.tr_logflags |= XFS_TRANS_PERM_LOG_RES; resp->tr_remove.tr_logres = xfs_calc_remove_reservation(mp); resp->tr_remove.tr_logcount = XFS_REMOVE_LOG_COUNT; resp->tr_remove.tr_logflags |= XFS_TRANS_PERM_LOG_RES; resp->tr_symlink.tr_logres = xfs_calc_symlink_reservation(mp); resp->tr_symlink.tr_logcount = XFS_SYMLINK_LOG_COUNT; resp->tr_symlink.tr_logflags |= XFS_TRANS_PERM_LOG_RES; resp->tr_create.tr_logres = xfs_calc_create_reservation(mp); resp->tr_create.tr_logcount = XFS_CREATE_LOG_COUNT; resp->tr_create.tr_logflags |= XFS_TRANS_PERM_LOG_RES; resp->tr_create_tmpfile.tr_logres = xfs_calc_create_tmpfile_reservation(mp); resp->tr_create_tmpfile.tr_logcount = XFS_CREATE_TMPFILE_LOG_COUNT; resp->tr_create_tmpfile.tr_logflags |= XFS_TRANS_PERM_LOG_RES; resp->tr_mkdir.tr_logres = xfs_calc_mkdir_reservation(mp); resp->tr_mkdir.tr_logcount = XFS_MKDIR_LOG_COUNT; resp->tr_mkdir.tr_logflags |= XFS_TRANS_PERM_LOG_RES; resp->tr_ifree.tr_logres = xfs_calc_ifree_reservation(mp); resp->tr_ifree.tr_logcount = XFS_INACTIVE_LOG_COUNT; resp->tr_ifree.tr_logflags |= XFS_TRANS_PERM_LOG_RES; resp->tr_addafork.tr_logres = xfs_calc_addafork_reservation(mp); resp->tr_addafork.tr_logcount = XFS_ADDAFORK_LOG_COUNT; resp->tr_addafork.tr_logflags |= XFS_TRANS_PERM_LOG_RES; resp->tr_attrinval.tr_logres = xfs_calc_attrinval_reservation(mp); resp->tr_attrinval.tr_logcount = XFS_ATTRINVAL_LOG_COUNT; resp->tr_attrinval.tr_logflags |= XFS_TRANS_PERM_LOG_RES; resp->tr_attrsetm.tr_logres = xfs_calc_attrsetm_reservation(mp); resp->tr_attrsetm.tr_logcount = XFS_ATTRSET_LOG_COUNT; resp->tr_attrsetm.tr_logflags |= XFS_TRANS_PERM_LOG_RES; resp->tr_attrrm.tr_logres = xfs_calc_attrrm_reservation(mp); resp->tr_attrrm.tr_logcount = XFS_ATTRRM_LOG_COUNT; resp->tr_attrrm.tr_logflags |= XFS_TRANS_PERM_LOG_RES; resp->tr_growrtalloc.tr_logres = xfs_calc_growrtalloc_reservation(mp); resp->tr_growrtalloc.tr_logcount = XFS_DEFAULT_PERM_LOG_COUNT; resp->tr_growrtalloc.tr_logflags |= XFS_TRANS_PERM_LOG_RES; resp->tr_qm_dqalloc.tr_logres = xfs_calc_qm_dqalloc_reservation(mp); resp->tr_qm_dqalloc.tr_logcount = XFS_WRITE_LOG_COUNT; resp->tr_qm_dqalloc.tr_logflags |= XFS_TRANS_PERM_LOG_RES; /* * The following transactions are logged in logical format with * a default log count. */ resp->tr_qm_setqlim.tr_logres = xfs_calc_qm_setqlim_reservation(mp); resp->tr_qm_setqlim.tr_logcount = XFS_DEFAULT_LOG_COUNT; resp->tr_qm_quotaoff.tr_logres = xfs_calc_qm_quotaoff_reservation(mp); resp->tr_qm_quotaoff.tr_logcount = XFS_DEFAULT_LOG_COUNT; resp->tr_qm_equotaoff.tr_logres = xfs_calc_qm_quotaoff_end_reservation(mp); resp->tr_qm_equotaoff.tr_logcount = XFS_DEFAULT_LOG_COUNT; resp->tr_sb.tr_logres = xfs_calc_sb_reservation(mp); resp->tr_sb.tr_logcount = XFS_DEFAULT_LOG_COUNT; /* The following transaction are logged in logical format */ resp->tr_ichange.tr_logres = xfs_calc_ichange_reservation(mp); resp->tr_growdata.tr_logres = xfs_calc_growdata_reservation(mp); resp->tr_fsyncts.tr_logres = xfs_calc_swrite_reservation(mp); resp->tr_writeid.tr_logres = xfs_calc_writeid_reservation(mp); resp->tr_attrsetrt.tr_logres = xfs_calc_attrsetrt_reservation(mp); resp->tr_clearagi.tr_logres = xfs_calc_clear_agi_bucket_reservation(mp); resp->tr_growrtzero.tr_logres = xfs_calc_growrtzero_reservation(mp); resp->tr_growrtfree.tr_logres = xfs_calc_growrtfree_reservation(mp); } partclone-0.2.86/src/xfs/xfs_trans_resv.h000066400000000000000000000111311262102574200204020ustar00rootroot00000000000000/* * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __XFS_TRANS_RESV_H__ #define __XFS_TRANS_RESV_H__ struct xfs_mount; /* * structure for maintaining pre-calculated transaction reservations. */ struct xfs_trans_res { uint tr_logres; /* log space unit in bytes per log ticket */ int tr_logcount; /* number of log operations per log ticket */ int tr_logflags; /* log flags, currently only used for indicating * a reservation request is permanent or not */ }; struct xfs_trans_resv { struct xfs_trans_res tr_write; /* extent alloc trans */ struct xfs_trans_res tr_itruncate; /* truncate trans */ struct xfs_trans_res tr_rename; /* rename trans */ struct xfs_trans_res tr_link; /* link trans */ struct xfs_trans_res tr_remove; /* unlink trans */ struct xfs_trans_res tr_symlink; /* symlink trans */ struct xfs_trans_res tr_create; /* create trans */ struct xfs_trans_res tr_create_tmpfile; /* create O_TMPFILE trans */ struct xfs_trans_res tr_mkdir; /* mkdir trans */ struct xfs_trans_res tr_ifree; /* inode free trans */ struct xfs_trans_res tr_ichange; /* inode update trans */ struct xfs_trans_res tr_growdata; /* fs data section grow trans */ struct xfs_trans_res tr_addafork; /* add inode attr fork trans */ struct xfs_trans_res tr_writeid; /* write setuid/setgid file */ struct xfs_trans_res tr_attrinval; /* attr fork buffer * invalidation */ struct xfs_trans_res tr_attrsetm; /* set/create an attribute at * mount time */ struct xfs_trans_res tr_attrsetrt; /* set/create an attribute at * runtime */ struct xfs_trans_res tr_attrrm; /* remove an attribute */ struct xfs_trans_res tr_clearagi; /* clear agi unlinked bucket */ struct xfs_trans_res tr_growrtalloc; /* grow realtime allocations */ struct xfs_trans_res tr_growrtzero; /* grow realtime zeroing */ struct xfs_trans_res tr_growrtfree; /* grow realtime freeing */ struct xfs_trans_res tr_qm_setqlim; /* adjust quota limits */ struct xfs_trans_res tr_qm_dqalloc; /* allocate quota on disk */ struct xfs_trans_res tr_qm_quotaoff; /* turn quota off */ struct xfs_trans_res tr_qm_equotaoff;/* end of turn quota off */ struct xfs_trans_res tr_sb; /* modify superblock */ struct xfs_trans_res tr_fsyncts; /* update timestamps on fsync */ }; /* shorthand way of accessing reservation structure */ #define M_RES(mp) (&(mp)->m_resv) /* * Per-extent log reservation for the allocation btree changes * involved in freeing or allocating an extent. * 2 trees * (2 blocks/level * max depth - 1) * block size */ #define XFS_ALLOCFREE_LOG_RES(mp,nx) \ ((nx) * (2 * XFS_FSB_TO_B((mp), 2 * (mp)->m_ag_maxlevels - 1))) #define XFS_ALLOCFREE_LOG_COUNT(mp,nx) \ ((nx) * (2 * (2 * (mp)->m_ag_maxlevels - 1))) /* * Per-directory log reservation for any directory change. * dir blocks: (1 btree block per level + data block + free block) * dblock size * bmap btree: (levels + 2) * max depth * block size * v2 directory blocks can be fragmented below the dirblksize down to the fsb * size, so account for that in the DAENTER macros. */ #define XFS_DIROP_LOG_RES(mp) \ (XFS_FSB_TO_B(mp, XFS_DAENTER_BLOCKS(mp, XFS_DATA_FORK)) + \ (XFS_FSB_TO_B(mp, XFS_DAENTER_BMAPS(mp, XFS_DATA_FORK) + 1))) #define XFS_DIROP_LOG_COUNT(mp) \ (XFS_DAENTER_BLOCKS(mp, XFS_DATA_FORK) + \ XFS_DAENTER_BMAPS(mp, XFS_DATA_FORK) + 1) /* * Various log count values. */ #define XFS_DEFAULT_LOG_COUNT 1 #define XFS_DEFAULT_PERM_LOG_COUNT 2 #define XFS_ITRUNCATE_LOG_COUNT 2 #define XFS_INACTIVE_LOG_COUNT 2 #define XFS_CREATE_LOG_COUNT 2 #define XFS_CREATE_TMPFILE_LOG_COUNT 2 #define XFS_MKDIR_LOG_COUNT 3 #define XFS_SYMLINK_LOG_COUNT 3 #define XFS_REMOVE_LOG_COUNT 2 #define XFS_LINK_LOG_COUNT 2 #define XFS_RENAME_LOG_COUNT 2 #define XFS_WRITE_LOG_COUNT 2 #define XFS_ADDAFORK_LOG_COUNT 2 #define XFS_ATTRINVAL_LOG_COUNT 1 #define XFS_ATTRSET_LOG_COUNT 3 #define XFS_ATTRRM_LOG_COUNT 3 void xfs_trans_resv_calc(struct xfs_mount *mp, struct xfs_trans_resv *resp); #endif /* __XFS_TRANS_RESV_H__ */ partclone-0.2.86/src/xfs/xfs_trans_space.h000066400000000000000000000071221262102574200205230ustar00rootroot00000000000000/* * Copyright (c) 2000,2005 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __XFS_TRANS_SPACE_H__ #define __XFS_TRANS_SPACE_H__ /* * Components of space reservations. */ #define XFS_MAX_CONTIG_EXTENTS_PER_BLOCK(mp) \ (((mp)->m_alloc_mxr[0]) - ((mp)->m_alloc_mnr[0])) #define XFS_EXTENTADD_SPACE_RES(mp,w) (XFS_BM_MAXLEVELS(mp,w) - 1) #define XFS_NEXTENTADD_SPACE_RES(mp,b,w)\ (((b + XFS_MAX_CONTIG_EXTENTS_PER_BLOCK(mp) - 1) / \ XFS_MAX_CONTIG_EXTENTS_PER_BLOCK(mp)) * \ XFS_EXTENTADD_SPACE_RES(mp,w)) #define XFS_DAENTER_1B(mp,w) \ ((w) == XFS_DATA_FORK ? (mp)->m_dir_geo->fsbcount : 1) #define XFS_DAENTER_DBS(mp,w) \ (XFS_DA_NODE_MAXDEPTH + (((w) == XFS_DATA_FORK) ? 2 : 0)) #define XFS_DAENTER_BLOCKS(mp,w) \ (XFS_DAENTER_1B(mp,w) * XFS_DAENTER_DBS(mp,w)) #define XFS_DAENTER_BMAP1B(mp,w) \ XFS_NEXTENTADD_SPACE_RES(mp, XFS_DAENTER_1B(mp, w), w) #define XFS_DAENTER_BMAPS(mp,w) \ (XFS_DAENTER_DBS(mp,w) * XFS_DAENTER_BMAP1B(mp,w)) #define XFS_DAENTER_SPACE_RES(mp,w) \ (XFS_DAENTER_BLOCKS(mp,w) + XFS_DAENTER_BMAPS(mp,w)) #define XFS_DAREMOVE_SPACE_RES(mp,w) XFS_DAENTER_BMAPS(mp,w) #define XFS_DIRENTER_MAX_SPLIT(mp,nl) 1 #define XFS_DIRENTER_SPACE_RES(mp,nl) \ (XFS_DAENTER_SPACE_RES(mp, XFS_DATA_FORK) * \ XFS_DIRENTER_MAX_SPLIT(mp,nl)) #define XFS_DIRREMOVE_SPACE_RES(mp) \ XFS_DAREMOVE_SPACE_RES(mp, XFS_DATA_FORK) #define XFS_IALLOC_SPACE_RES(mp) \ ((mp)->m_ialloc_blks + \ (xfs_sb_version_hasfinobt(&mp->m_sb) ? 2 : 1 * \ ((mp)->m_in_maxlevels - 1))) /* * Space reservation values for various transactions. */ #define XFS_ADDAFORK_SPACE_RES(mp) \ ((mp)->m_dir_geo->fsbcount + XFS_DAENTER_BMAP1B(mp, XFS_DATA_FORK)) #define XFS_ATTRRM_SPACE_RES(mp) \ XFS_DAREMOVE_SPACE_RES(mp, XFS_ATTR_FORK) /* This macro is not used - see inline code in xfs_attr_set */ #define XFS_ATTRSET_SPACE_RES(mp, v) \ (XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK) + XFS_B_TO_FSB(mp, v)) #define XFS_CREATE_SPACE_RES(mp,nl) \ (XFS_IALLOC_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,nl)) #define XFS_DIOSTRAT_SPACE_RES(mp, v) \ (XFS_EXTENTADD_SPACE_RES(mp, XFS_DATA_FORK) + (v)) #define XFS_GROWFS_SPACE_RES(mp) \ (2 * (mp)->m_ag_maxlevels) #define XFS_GROWFSRT_SPACE_RES(mp,b) \ ((b) + XFS_EXTENTADD_SPACE_RES(mp, XFS_DATA_FORK)) #define XFS_LINK_SPACE_RES(mp,nl) \ XFS_DIRENTER_SPACE_RES(mp,nl) #define XFS_MKDIR_SPACE_RES(mp,nl) \ (XFS_IALLOC_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,nl)) #define XFS_QM_DQALLOC_SPACE_RES(mp) \ (XFS_EXTENTADD_SPACE_RES(mp, XFS_DATA_FORK) + \ XFS_DQUOT_CLUSTER_SIZE_FSB) #define XFS_QM_QINOCREATE_SPACE_RES(mp) \ XFS_IALLOC_SPACE_RES(mp) #define XFS_REMOVE_SPACE_RES(mp) \ XFS_DIRREMOVE_SPACE_RES(mp) #define XFS_RENAME_SPACE_RES(mp,nl) \ (XFS_DIRREMOVE_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,nl)) #define XFS_SYMLINK_SPACE_RES(mp,nl,b) \ (XFS_IALLOC_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,nl) + (b)) #define XFS_IFREE_SPACE_RES(mp) \ (xfs_sb_version_hasfinobt(&mp->m_sb) ? (mp)->m_in_maxlevels : 0) #endif /* __XFS_TRANS_SPACE_H__ */ partclone-0.2.86/src/xfs/xfs_types.h000066400000000000000000000111411262102574200173610ustar00rootroot00000000000000/* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __XFS_TYPES_H__ #define __XFS_TYPES_H__ typedef __uint32_t prid_t; /* project ID */ typedef __uint32_t xfs_agblock_t; /* blockno in alloc. group */ typedef __uint32_t xfs_agino_t; /* inode # within allocation grp */ typedef __uint32_t xfs_extlen_t; /* extent length in blocks */ typedef __uint32_t xfs_agnumber_t; /* allocation group number */ typedef __int32_t xfs_extnum_t; /* # of extents in a file */ typedef __int16_t xfs_aextnum_t; /* # extents in an attribute fork */ typedef __int64_t xfs_fsize_t; /* bytes in a file */ typedef __uint64_t xfs_ufsize_t; /* unsigned bytes in a file */ typedef __int32_t xfs_suminfo_t; /* type of bitmap summary info */ typedef __int32_t xfs_rtword_t; /* word type for bitmap manipulations */ typedef __int64_t xfs_lsn_t; /* log sequence number */ typedef __int32_t xfs_tid_t; /* transaction identifier */ typedef __uint32_t xfs_dablk_t; /* dir/attr block number (in file) */ typedef __uint32_t xfs_dahash_t; /* dir/attr hash value */ typedef __uint64_t xfs_fsblock_t; /* blockno in filesystem (agno|agbno) */ typedef __uint64_t xfs_rfsblock_t; /* blockno in filesystem (raw) */ typedef __uint64_t xfs_rtblock_t; /* extent (block) in realtime area */ typedef __uint64_t xfs_fileoff_t; /* block number in a file */ typedef __uint64_t xfs_filblks_t; /* number of blocks in a file */ typedef __int64_t xfs_srtblock_t; /* signed version of xfs_rtblock_t */ typedef __int64_t xfs_sfiloff_t; /* signed block number in a file */ /* * Null values for the types. */ #define NULLFSBLOCK ((xfs_fsblock_t)-1) #define NULLRFSBLOCK ((xfs_rfsblock_t)-1) #define NULLRTBLOCK ((xfs_rtblock_t)-1) #define NULLFILEOFF ((xfs_fileoff_t)-1) #define NULLAGBLOCK ((xfs_agblock_t)-1) #define NULLAGNUMBER ((xfs_agnumber_t)-1) #define NULLEXTNUM ((xfs_extnum_t)-1) #define NULLCOMMITLSN ((xfs_lsn_t)-1) #define NULLFSINO ((xfs_ino_t)-1) #define NULLAGINO ((xfs_agino_t)-1) /* * Max values for extlen, extnum, aextnum. */ #define MAXEXTLEN ((xfs_extlen_t)0x001fffff) /* 21 bits */ #define MAXEXTNUM ((xfs_extnum_t)0x7fffffff) /* signed int */ #define MAXAEXTNUM ((xfs_aextnum_t)0x7fff) /* signed short */ /* * Minimum and maximum blocksize and sectorsize. * The blocksize upper limit is pretty much arbitrary. * The sectorsize upper limit is due to sizeof(sb_sectsize). * CRC enable filesystems use 512 byte inodes, meaning 512 byte block sizes * cannot be used. */ #define XFS_MIN_BLOCKSIZE_LOG 9 /* i.e. 512 bytes */ #define XFS_MAX_BLOCKSIZE_LOG 16 /* i.e. 65536 bytes */ #define XFS_MIN_BLOCKSIZE (1 << XFS_MIN_BLOCKSIZE_LOG) #define XFS_MAX_BLOCKSIZE (1 << XFS_MAX_BLOCKSIZE_LOG) #define XFS_MIN_CRC_BLOCKSIZE (1 << (XFS_MIN_BLOCKSIZE_LOG + 1)) #define XFS_MIN_SECTORSIZE_LOG 9 /* i.e. 512 bytes */ #define XFS_MAX_SECTORSIZE_LOG 15 /* i.e. 32768 bytes */ #define XFS_MIN_SECTORSIZE (1 << XFS_MIN_SECTORSIZE_LOG) #define XFS_MAX_SECTORSIZE (1 << XFS_MAX_SECTORSIZE_LOG) /* * Inode fork identifiers. */ #define XFS_DATA_FORK 0 #define XFS_ATTR_FORK 1 /* * Min numbers of data/attr fork btree root pointers. */ #define MINDBTPTRS 3 #define MINABTPTRS 2 /* * MAXNAMELEN is the length (including the terminating null) of * the longest permissible file (component) name. */ #define MAXNAMELEN 256 typedef enum { XFS_LOOKUP_EQi, XFS_LOOKUP_LEi, XFS_LOOKUP_GEi } xfs_lookup_t; typedef enum { XFS_BTNUM_BNOi, XFS_BTNUM_CNTi, XFS_BTNUM_BMAPi, XFS_BTNUM_INOi, XFS_BTNUM_FINOi, XFS_BTNUM_MAX } xfs_btnum_t; struct xfs_name { const unsigned char *name; int len; int type; }; /* * uid_t and gid_t are hard-coded to 32 bits in the inode. * Hence, an 'id' in a dquot is 32 bits.. */ typedef __uint32_t xfs_dqid_t; /* * Constants for bit manipulations. */ #define XFS_NBBYLOG 3 /* log2(NBBY) */ #define XFS_WORDLOG 2 /* log2(sizeof(xfs_rtword_t)) */ #define XFS_NBWORDLOG (XFS_NBBYLOG + XFS_WORDLOG) #define XFS_NBWORD (1 << XFS_NBWORDLOG) #define XFS_WORDMASK ((1 << XFS_WORDLOG) - 1) #endif /* __XFS_TYPES_H__ */ partclone-0.2.86/src/xfs/xqm.h000066400000000000000000000142331262102574200161470ustar00rootroot00000000000000/* * Copyright (c) 1995, 2001, 2004-2005 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __XQM_H__ #define __XQM_H__ #include /* * Disk quota - quotactl(2) commands for the XFS Quota Manager (XQM). */ #define XQM_CMD(x) (('X'<<8)+(x)) /* note: forms first QCMD argument */ #define Q_XQUOTAON XQM_CMD(1) /* enable accounting/enforcement */ #define Q_XQUOTAOFF XQM_CMD(2) /* disable accounting/enforcement */ #define Q_XGETQUOTA XQM_CMD(3) /* get disk limits and usage */ #define Q_XSETQLIM XQM_CMD(4) /* set disk limits */ #define Q_XGETQSTAT XQM_CMD(5) /* get quota subsystem status */ #define Q_XQUOTARM XQM_CMD(6) /* free disk space used by dquots */ #define Q_XQUOTASYNC XQM_CMD(7) /* delalloc flush, updates dquots */ /* * fs_disk_quota structure: * * This contains the current quota information regarding a user/proj/group. * It is 64-bit aligned, and all the blk units are in BBs (Basic Blocks) of * 512 bytes. */ #define FS_DQUOT_VERSION 1 /* fs_disk_quota.d_version */ typedef struct fs_disk_quota { __s8 d_version; /* version of this structure */ __s8 d_flags; /* XFS_{USER,PROJ,GROUP}_QUOTA */ __u16 d_fieldmask; /* field specifier */ __u32 d_id; /* user, project, or group ID */ __u64 d_blk_hardlimit;/* absolute limit on disk blks */ __u64 d_blk_softlimit;/* preferred limit on disk blks */ __u64 d_ino_hardlimit;/* maximum # allocated inodes */ __u64 d_ino_softlimit;/* preferred inode limit */ __u64 d_bcount; /* # disk blocks owned by the user */ __u64 d_icount; /* # inodes owned by the user */ __s32 d_itimer; /* zero if within inode limits */ /* if not, we refuse service */ __s32 d_btimer; /* similar to above; for disk blocks */ __u16 d_iwarns; /* # warnings issued wrt num inodes */ __u16 d_bwarns; /* # warnings issued wrt disk blocks */ __s32 d_padding2; /* padding2 - for future use */ __u64 d_rtb_hardlimit;/* absolute limit on realtime blks */ __u64 d_rtb_softlimit;/* preferred limit on RT disk blks */ __u64 d_rtbcount; /* # realtime blocks owned */ __s32 d_rtbtimer; /* similar to above; for RT disk blks */ __u16 d_rtbwarns; /* # warnings issued wrt RT disk blks */ __s16 d_padding3; /* padding3 - for future use */ char d_padding4[8]; /* yet more padding */ } fs_disk_quota_t; /* * These fields are sent to Q_XSETQLIM to specify fields that need to change. */ #define FS_DQ_ISOFT (1<<0) #define FS_DQ_IHARD (1<<1) #define FS_DQ_BSOFT (1<<2) #define FS_DQ_BHARD (1<<3) #define FS_DQ_RTBSOFT (1<<4) #define FS_DQ_RTBHARD (1<<5) #define FS_DQ_LIMIT_MASK (FS_DQ_ISOFT | FS_DQ_IHARD | FS_DQ_BSOFT | \ FS_DQ_BHARD | FS_DQ_RTBSOFT | FS_DQ_RTBHARD) /* * These timers can only be set in super user's dquot. For others, timers are * automatically started and stopped. Superusers timer values set the limits * for the rest. In case these values are zero, the DQ_{F,B}TIMELIMIT values * defined below are used. * These values also apply only to the d_fieldmask field for Q_XSETQLIM. */ #define FS_DQ_BTIMER (1<<6) #define FS_DQ_ITIMER (1<<7) #define FS_DQ_RTBTIMER (1<<8) #define FS_DQ_TIMER_MASK (FS_DQ_BTIMER | FS_DQ_ITIMER | FS_DQ_RTBTIMER) /* * Warning counts are set in both super user's dquot and others. For others, * warnings are set/cleared by the administrators (or automatically by going * below the soft limit). Superusers warning values set the warning limits * for the rest. In case these values are zero, the DQ_{F,B}WARNLIMIT values * defined below are used. * These values also apply only to the d_fieldmask field for Q_XSETQLIM. */ #define FS_DQ_BWARNS (1<<9) #define FS_DQ_IWARNS (1<<10) #define FS_DQ_RTBWARNS (1<<11) #define FS_DQ_WARNS_MASK (FS_DQ_BWARNS | FS_DQ_IWARNS | FS_DQ_RTBWARNS) /* * Various flags related to quotactl(2). Only relevant to XFS filesystems. */ #define XFS_QUOTA_UDQ_ACCT (1<<0) /* user quota accounting */ #define XFS_QUOTA_UDQ_ENFD (1<<1) /* user quota limits enforcement */ #define XFS_QUOTA_GDQ_ACCT (1<<2) /* group quota accounting */ #define XFS_QUOTA_GDQ_ENFD (1<<3) /* group quota limits enforcement */ #define XFS_QUOTA_PDQ_ACCT (1<<4) /* project quota accounting */ #define XFS_QUOTA_PDQ_ENFD (1<<5) /* project quota limits enforcement */ #define XFS_USER_QUOTA (1<<0) /* user quota type */ #define XFS_PROJ_QUOTA (1<<1) /* project quota type */ #define XFS_GROUP_QUOTA (1<<2) /* group quota type */ /* * fs_quota_stat is the struct returned in Q_XGETQSTAT for a given file system. * Provides a centralized way to get meta information about the quota subsystem. * eg. space taken up for user and group quotas, number of dquots currently * incore. */ #define FS_QSTAT_VERSION 1 /* fs_quota_stat.qs_version */ /* * Some basic information about 'quota files'. */ typedef struct fs_qfilestat { __u64 qfs_ino; /* inode number */ __u64 qfs_nblks; /* number of BBs 512-byte-blks */ __u32 qfs_nextents; /* number of extents */ } fs_qfilestat_t; typedef struct fs_quota_stat { __s8 qs_version; /* version number for future changes */ __u16 qs_flags; /* XFS_QUOTA_{U,P,G}DQ_{ACCT,ENFD} */ __s8 qs_pad; /* unused */ fs_qfilestat_t qs_uquota; /* user quota storage information */ fs_qfilestat_t qs_gquota; /* group quota storage information */ __u32 qs_incoredqs; /* number of dquots incore */ __s32 qs_btimelimit; /* limit for blks timer */ __s32 qs_itimelimit; /* limit for inodes timer */ __s32 qs_rtbtimelimit;/* limit for rt blks timer */ __u16 qs_bwarnlimit; /* limit for num warnings */ __u16 qs_iwarnlimit; /* limit for num warnings */ } fs_quota_stat_t; #endif /* __XQM_H__ */ partclone-0.2.86/src/xfsclone.c000066400000000000000000000307771262102574200163710ustar00rootroot00000000000000/** * xfsclone.c - part of Partclone project * * Copyright (c) 2007~ Thomas Tsai * * read xfs super block and bitmap, reference xfs_copy.c * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ #define _LARGEFILE64_SOURCE #include #include #include #include "xfs/libxfs.h" #include "partclone.h" #include "xfsclone.h" #include "progress.h" #include "fs_common.h" #undef crc32 char *EXECNAME = "partclone.xfs"; extern fs_cmd_opt fs_opt; int source_fd = -1; int first_residue; progress_bar prog; unsigned long long checked; int bitmap_done = 0; unsigned long* xfs_bitmap; xfs_mount_t *mp; xfs_mount_t mbuf; libxfs_init_t xargs; unsigned int source_blocksize; /* source filesystem blocksize */ unsigned int source_sectorsize; /* source disk sectorsize */ void *thread_update_bitmap_pui(void *arg); #define rounddown(x, y) (((x)/(y))*(y)) void get_sb(xfs_sb_t *sbp, xfs_off_t off, int size, xfs_agnumber_t agno) { xfs_dsb_t *buf; int rval = 0; buf = memalign(libxfs_device_alignment(), size); if (buf == NULL) { log_mesg(0, 1, 1, fs_opt.debug, "%s: error reading superblock %u -- failed to memalign buffer\n", __FILE__, agno); } memset(buf, 0, size); memset(sbp, 0, sizeof(*sbp)); /* try and read it first */ if (lseek64(source_fd, off, SEEK_SET) != off) { free(buf); log_mesg(0, 1, 1, fs_opt.debug, "%s: error reading superblock %u -- seek to offset %" PRId64 " failed\n", __FILE__, agno, off); } if ((rval = read(source_fd, buf, size)) != size) { log_mesg(0, 1, 1, fs_opt.debug, "%s: superblock read failed, offset %" PRId64 ", size %d, ag %u, rval %d\n", __FILE__, off, size, agno, rval); } libxfs_sb_from_disk(sbp, buf); //rval = verify_sb((char *)buf, sbp, agno == 0); free(buf); //return rval; } static void set_bitmap(unsigned long* bitmap, uint64_t start, int count) { uint64_t block; for (block = start; block < start+count; block++){ pc_clear_bit(block, bitmap); log_mesg(3, 0, 0, fs_opt.debug, "%s: block %i is free\n", __FILE__, block); checked++; } } // copy from xfs_db freesp .... typedef enum typnm { TYP_AGF, TYP_AGFL, TYP_AGI, TYP_ATTR, TYP_BMAPBTA, TYP_BMAPBTD, TYP_BNOBT, TYP_CNTBT, TYP_DATA, TYP_DIR2, TYP_DQBLK, TYP_INOBT, TYP_INODATA, TYP_INODE, TYP_LOG, TYP_RTBITMAP, TYP_RTSUMMARY, TYP_SB, TYP_SYMLINK, TYP_TEXT, TYP_NONE } typnm_t; static void addtohist( xfs_agnumber_t agno, xfs_agblock_t agbno, xfs_extlen_t len) { unsigned long long start_block; log_mesg(1, 0, 0, fs_opt.debug, "%s: add %8d %8d %8d\n", __FILE__, agno, agbno, len); start_block = (agno*mp->m_sb.sb_agblocks) + agbno; set_bitmap(xfs_bitmap, start_block, len); } static void scan_sbtree( xfs_agf_t *agf, xfs_agblock_t root, typnm_t typ, int nlevels, void (*func)(struct xfs_btree_block *block, typnm_t typ, int level, xfs_agf_t *agf)) { xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno); struct xfs_buf *bp; int blkbb = 1 << mp->m_blkbb_log; void *data; //push_cur(); //set_cur(&typtab[typ], XFS_AGB_TO_DADDR(mp, seqno, root), // blkbb, DB_RING_IGN, NULL); bp = libxfs_readbuf(mp->m_ddev_targp, XFS_AGB_TO_DADDR(mp, seqno, root), blkbb, 0, NULL); data = bp->b_addr; if (data == NULL) { log_mesg(0, 0, 0, fs_opt.debug, "%s: can't read btree block %u/%u\n", __FILE__, seqno, root); return; } (*func)(data, typ, nlevels - 1, agf); //pop_cur(); } static void scanfunc_bno( struct xfs_btree_block *block, typnm_t typ, int level, xfs_agf_t *agf) { int i; xfs_alloc_ptr_t *pp; xfs_alloc_rec_t *rp; if (!(be32_to_cpu(block->bb_magic) == XFS_ABTB_MAGIC || be32_to_cpu(block->bb_magic) == XFS_ABTB_CRC_MAGIC)){ log_mesg(0, 0, 0, fs_opt.debug, "%s: bb_magic error\n", __FILE__); return; } if (level == 0) { rp = XFS_ALLOC_REC_ADDR(mp, block, 1); for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) addtohist(be32_to_cpu(agf->agf_seqno), be32_to_cpu(rp[i].ar_startblock), be32_to_cpu(rp[i].ar_blockcount)); return; } pp = XFS_ALLOC_PTR_ADDR(mp, block, 1, mp->m_alloc_mxr[1]); for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) scan_sbtree(agf, be32_to_cpu(pp[i]), typ, level, scanfunc_bno); } static void scan_freelist( xfs_agf_t *agf) { xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno); xfs_agfl_t *agfl; xfs_agblock_t bno; int i; __be32 *agfl_bno; struct xfs_buf *bp; const struct xfs_buf_ops *ops = NULL; if (be32_to_cpu(agf->agf_flcount) == 0) return; //push_cur(); //set_cur(&typtab[TYP_AGFL], XFS_AG_DADDR(mp, seqno, XFS_AGFL_DADDR(mp)), // XFS_FSS_TO_BB(mp, 1), DB_RING_IGN, NULL); //agfl = iocur_top->data; bp = libxfs_readbuf(mp->m_ddev_targp, XFS_AG_DADDR(mp, seqno, XFS_AGFL_DADDR(mp)), XFS_FSS_TO_BB(mp, 1), 0, ops); agfl = bp->b_addr; i = be32_to_cpu(agf->agf_flfirst); /* open coded XFS_BUF_TO_AGFL_BNO */ agfl_bno = xfs_sb_version_hascrc(&mp->m_sb) ? &agfl->agfl_bno[0] : (__be32 *)agfl; /* verify agf values before proceeding */ if (be32_to_cpu(agf->agf_flfirst) >= XFS_AGFL_SIZE(mp) || be32_to_cpu(agf->agf_fllast) >= XFS_AGFL_SIZE(mp)) { log_mesg(0, 0, 0, fs_opt.debug, "%s: agf %d freelist blocks bad, skipping freelist scan\n", __FILE__, i); //pop_cur(); return; } for (;;) { bno = be32_to_cpu(agfl_bno[i]); addtohist(seqno, bno, 1); if (i == be32_to_cpu(agf->agf_fllast)) break; if (++i == XFS_AGFL_SIZE(mp)) i = 0; } //pop_cur(); } static void scan_ag( xfs_agnumber_t agno) { xfs_agf_t *agf; struct xfs_buf *bp; const struct xfs_buf_ops *ops = NULL; //push_cur(); //set_cur(&typtab[TYP_AGF], XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR(mp)), // XFS_FSS_TO_BB(mp, 1), DB_RING_IGN, NULL); //agf = iocur_top->data; bp = libxfs_readbuf(mp->m_ddev_targp, XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR(mp)), XFS_FSS_TO_BB(mp, 1), 0, ops); agf = bp->b_addr; scan_freelist(agf); scan_sbtree(agf, be32_to_cpu(agf->agf_roots[XFS_BTNUM_BNO]), TYP_BNOBT, be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNO]), scanfunc_bno); //pop_cur(); } static void fs_open(char* device) { int open_flags; struct stat statbuf; int source_is_file = 0; //xfs_buf_t *sbp; xfs_sb_t *sb; int tmp_residue; /* open up source -- is it a file? */ open_flags = O_RDONLY; if ((source_fd = open(device, open_flags)) < 0) { log_mesg(0, 1, 1, fs_opt.debug, "%s: Couldn't open source partition %s\n", __FILE__, device); }else{ log_mesg(0, 0, 0, fs_opt.debug, "%s: Open %s successfully", __FILE__, device); } if (fstat(source_fd, &statbuf) < 0) { log_mesg(0, 1, 1, fs_opt.debug, "%s: Couldn't stat source partition\n", __FILE__); } if (S_ISREG(statbuf.st_mode)){ log_mesg(1, 0, 0, fs_opt.debug, "%s: source is file\n", __FILE__); source_is_file = 1; } /* prepare the libxfs_init structure */ memset(&xargs, 0, sizeof(xargs)); xargs.isdirect = LIBXFS_DIRECT; xargs.isreadonly = LIBXFS_ISREADONLY; if (source_is_file) { xargs.dname = device; xargs.disfile = 1; } else xargs.volname = device; if (libxfs_init(&xargs) == 0) { log_mesg(0, 1, 1, fs_opt.debug, "%s: libxfs_init error. Please repaire %s partition.\n", __FILE__, device); } /* prepare the mount structure */ memset(&mbuf, 0, sizeof(xfs_mount_t)); sb = &mbuf.m_sb; get_sb(sb, 0, XFS_MAX_SECTORSIZE, 0); //sbp = libxfs_readbuf(xargs.ddev, XFS_SB_DADDR, 1, 0, ops); //memset(&mbuf, 0, sizeof(xfs_mount_t)); //sb = &mbuf.m_sb; //libxfs_sb_from_disk(sb, XFS_BUF_TO_SBP(sbp)); mp = libxfs_mount(&mbuf, sb, xargs.ddev, xargs.logdev, xargs.rtdev, 1); if (mp == NULL) { log_mesg(0, 1, 1, fs_opt.debug, "%s: %s filesystem failed to initialize\nAborting.\n", __FILE__, device); } else if (mp->m_sb.sb_inprogress) { log_mesg(0, 1, 1, fs_opt.debug, "%s: %s filesystem failed to initialize\nAborting(inprogress).\n", __FILE__, device); } else if (mp->m_sb.sb_logstart == 0) { log_mesg(0, 1, 1, fs_opt.debug, "%s: %s has an external log.\nAborting.\n", __FILE__, device); } else if (mp->m_sb.sb_rextents != 0) { log_mesg(0, 1, 1, fs_opt.debug, "%s: %s has a real-time section.\nAborting.\n", __FILE__, device); } source_blocksize = mp->m_sb.sb_blocksize; source_sectorsize = mp->m_sb.sb_sectsize; log_mesg(2, 0, 0, fs_opt.debug, "%s: source_blocksize %i source_sectorsize = %i\n", __FILE__, source_blocksize, source_sectorsize); if (source_blocksize > source_sectorsize) { /* get number of leftover sectors in last block of ag header */ tmp_residue = ((XFS_AGFL_DADDR(mp) + 1) * source_sectorsize) % source_blocksize; first_residue = (tmp_residue == 0) ? 0 : source_blocksize - tmp_residue; log_mesg(2, 0, 0, fs_opt.debug, "%s: first_residue %i tmp_residue %i\n", __FILE__, first_residue, tmp_residue); } else if (source_blocksize == source_sectorsize) { first_residue = 0; } else { log_mesg(0, 1, 1, fs_opt.debug, "%s: Error: filesystem block size is smaller than the disk sectorsize.\nAborting XFS copy now.\n", __FILE__); } /* end of xfs open */ log_mesg(3, 0, 0, fs_opt.debug, "%s: blcos size= %i\n", __FILE__, mp->m_sb.sb_blocksize); log_mesg(3, 0, 0, fs_opt.debug, "%s: total b= %lli\n", __FILE__, mp->m_sb.sb_dblocks); log_mesg(3, 0, 0, fs_opt.debug, "%s: free block= %lli\n", __FILE__, mp->m_sb.sb_fdblocks); log_mesg(3, 0, 0, fs_opt.debug, "%s: used block= %lli\n", __FILE__, (mp->m_sb.sb_dblocks - mp->m_sb.sb_fdblocks)); log_mesg(3, 0, 0, fs_opt.debug, "%s: device size= %lli\n", __FILE__, (mp->m_sb.sb_blocksize * mp->m_sb.sb_dblocks)); } static void fs_close() { libxfs_device_close(xargs.ddev); log_mesg(0, 0, 0, fs_opt.debug, "%s: fs_close\n", __FILE__); } extern void initial_image_hdr(char* device, image_head* image_hdr) { fs_open(device); strncpy(image_hdr->magic, IMAGE_MAGIC, IMAGE_MAGIC_SIZE); strncpy(image_hdr->fs, xfs_MAGIC, FS_MAGIC_SIZE); image_hdr->block_size = mp->m_sb.sb_blocksize; image_hdr->totalblock = mp->m_sb.sb_dblocks; image_hdr->usedblocks = mp->m_sb.sb_dblocks - mp->m_sb.sb_fdblocks; image_hdr->device_size = (image_hdr->totalblock * image_hdr->block_size); log_mesg(1, 0, 0, fs_opt.debug, "%s: blcos size= %i\n", __FILE__, mp->m_sb.sb_blocksize); log_mesg(1, 0, 0, fs_opt.debug, "%s: total b= %lli\n", __FILE__, mp->m_sb.sb_dblocks); log_mesg(1, 0, 0, fs_opt.debug, "%s: free block= %lli\n", __FILE__, mp->m_sb.sb_fdblocks); log_mesg(1, 0, 0, fs_opt.debug, "%s: used block= %lli\n", __FILE__, (mp->m_sb.sb_dblocks - mp->m_sb.sb_fdblocks)); log_mesg(1, 0, 0, fs_opt.debug, "%s: device size= %lli\n", __FILE__, (mp->m_sb.sb_blocksize*mp->m_sb.sb_dblocks)); fs_close(); } extern void readbitmap(char* device, image_head image_hdr, unsigned long* bitmap, int pui) { xfs_agnumber_t agno = 0; xfs_agnumber_t num_ags; int start = 0; int bit_size = 1; int bres; pthread_t prog_bitmap_thread; uint64_t bused = 0; uint64_t bfree = 0; unsigned long long current_block = 0; xfs_bitmap = bitmap; for(current_block = 0; current_block <= image_hdr.totalblock; current_block++){ pc_set_bit(current_block, bitmap); } /// init progress progress_init(&prog, start, image_hdr.totalblock, image_hdr.totalblock, BITMAP, bit_size); checked = 0; /** * thread to print progress */ bres = pthread_create(&prog_bitmap_thread, NULL, thread_update_bitmap_pui, NULL); if(bres){ log_mesg(0, 1, 1, fs_opt.debug, "%s, %i, thread create error\n", __func__, __LINE__); } fs_open(device); num_ags = mp->m_sb.sb_agcount; log_mesg(1, 0, 0, fs_opt.debug, "ags = %i\n", num_ags); for (agno = 0; agno < num_ags ; agno++) { /* read in first blocks of the ag */ scan_ag(agno); } for(current_block = 0; current_block <= image_hdr.totalblock; current_block++){ if(pc_test_bit(current_block, bitmap)) bused++; else bfree++; } log_mesg(0, 0, 0, fs_opt.debug, "%s: bused = %lli, bfree = %lli\n", __FILE__, bused, bfree); fs_close(); bitmap_done = 1; update_pui(&prog, 1, 1, 1); } void *thread_update_bitmap_pui(void *arg){ while (bitmap_done == 0) { update_pui(&prog, checked, checked, 0); sleep(2); } pthread_exit("exit"); } partclone-0.2.86/src/xfsclone.h000066400000000000000000000012201262102574200163530ustar00rootroot00000000000000/** * xfsclone.h - part of Partclone project * * Copyright (c) 2007~ Thomas Tsai * * read xfs super block and bitmap * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ #undef crc32 /// readbitmap - read bitmap extern void readbitmap(char* device, image_head image_hdr, unsigned long* bitmap, int pui); /// read super block and write to image head extern void initial_image_hdr(char* device, image_head* image_hdr); partclone-0.2.86/test-driver000077500000000000000000000110401262102574200157710ustar00rootroot00000000000000#! /bin/sh # test-driver - basic testsuite driver script. scriptversion=2013-07-13.22; # UTC # Copyright (C) 2011-2014 Free Software Foundation, Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # This file is maintained in Automake, please report # bugs to or send patches to # . # Make unconditional expansion of undefined variables an error. This # helps a lot in preventing typo-related bugs. set -u usage_error () { echo "$0: $*" >&2 print_usage >&2 exit 2 } print_usage () { cat <$log_file 2>&1 estatus=$? if test $enable_hard_errors = no && test $estatus -eq 99; then tweaked_estatus=1 else tweaked_estatus=$estatus fi case $tweaked_estatus:$expect_failure in 0:yes) col=$red res=XPASS recheck=yes gcopy=yes;; 0:*) col=$grn res=PASS recheck=no gcopy=no;; 77:*) col=$blu res=SKIP recheck=no gcopy=yes;; 99:*) col=$mgn res=ERROR recheck=yes gcopy=yes;; *:yes) col=$lgn res=XFAIL recheck=no gcopy=yes;; *:*) col=$red res=FAIL recheck=yes gcopy=yes;; esac # Report the test outcome and exit status in the logs, so that one can # know whether the test passed or failed simply by looking at the '.log' # file, without the need of also peaking into the corresponding '.trs' # file (automake bug#11814). echo "$res $test_name (exit status: $estatus)" >>$log_file # Report outcome to console. echo "${col}${res}${std}: $test_name" # Register the test result, and other relevant metadata. echo ":test-result: $res" > $trs_file echo ":global-test-result: $res" >> $trs_file echo ":recheck: $recheck" >> $trs_file echo ":copy-in-global-log: $gcopy" >> $trs_file # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: partclone-0.2.86/tests/000077500000000000000000000000001262102574200147415ustar00rootroot00000000000000partclone-0.2.86/tests/Makefile000066400000000000000000000635111262102574200164070ustar00rootroot00000000000000# Makefile.in generated by automake 1.15 from Makefile.am. # tests/Makefile. Generated from Makefile.in by configure. # Copyright (C) 1994-2014 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/partclone pkgincludedir = $(includedir)/partclone pkglibdir = $(libdir)/partclone pkglibexecdir = $(libexecdir)/partclone am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = x86_64-unknown-linux-gnu host_triplet = x86_64-unknown-linux-gnu #am__append_1 = ext2.test \ # ext3.test ext4.test #am__append_2 = btrfs.test #am__append_3 = fat.test #am__append_4 = reiserfs.test #if ENABLE_REISER4 #TESTS += reiser4.test #endif #am__append_5 = hfsplus.test #am__append_6 = xfs.test #am__append_7 = exfat.test #am__append_8 = f2fs.test #am__append_9 = ntfs.test #if ENABLE_UFS #TESTS += ufs.test #endif #if ENABLE_VMFS #TESTS += vmfs.test #endif #am__append_10 = jfs.test #am__append_11 = btrfs.test #am__append_12 = exfat.test #am__append_13 = nilfs2.test ##am__append_14 = ncursesw.test subdir = tests ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/gettext.m4 \ $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_$(V)) am__v_P_ = $(am__v_P_$(AM_DEFAULT_VERBOSITY)) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_$(V)) am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_$(V)) am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__tty_colors_dummy = \ mgn= red= grn= lgn= blu= brg= std=; \ am__color_tests=no am__tty_colors = { \ $(am__tty_colors_dummy); \ if test "X$(AM_COLOR_TESTS)" = Xno; then \ am__color_tests=no; \ elif test "X$(AM_COLOR_TESTS)" = Xalways; then \ am__color_tests=yes; \ elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \ am__color_tests=yes; \ fi; \ if test $$am__color_tests = yes; then \ red=''; \ grn=''; \ lgn=''; \ blu=''; \ mgn=''; \ brg=''; \ std=''; \ fi; \ } am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__recheck_rx = ^[ ]*:recheck:[ ]* am__global_test_result_rx = ^[ ]*:global-test-result:[ ]* am__copy_in_global_log_rx = ^[ ]*:copy-in-global-log:[ ]* # A command that, given a newline-separated list of test names on the # standard input, print the name of the tests that are to be re-run # upon "make recheck". am__list_recheck_tests = $(AWK) '{ \ recheck = 1; \ while ((rc = (getline line < ($$0 ".trs"))) != 0) \ { \ if (rc < 0) \ { \ if ((getline line2 < ($$0 ".log")) < 0) \ recheck = 0; \ break; \ } \ else if (line ~ /$(am__recheck_rx)[nN][Oo]/) \ { \ recheck = 0; \ break; \ } \ else if (line ~ /$(am__recheck_rx)[yY][eE][sS]/) \ { \ break; \ } \ }; \ if (recheck) \ print $$0; \ close ($$0 ".trs"); \ close ($$0 ".log"); \ }' # A command that, given a newline-separated list of test names on the # standard input, create the global log from their .trs and .log files. am__create_global_log = $(AWK) ' \ function fatal(msg) \ { \ print "fatal: making $@: " msg | "cat >&2"; \ exit 1; \ } \ function rst_section(header) \ { \ print header; \ len = length(header); \ for (i = 1; i <= len; i = i + 1) \ printf "="; \ printf "\n\n"; \ } \ { \ copy_in_global_log = 1; \ global_test_result = "RUN"; \ while ((rc = (getline line < ($$0 ".trs"))) != 0) \ { \ if (rc < 0) \ fatal("failed to read from " $$0 ".trs"); \ if (line ~ /$(am__global_test_result_rx)/) \ { \ sub("$(am__global_test_result_rx)", "", line); \ sub("[ ]*$$", "", line); \ global_test_result = line; \ } \ else if (line ~ /$(am__copy_in_global_log_rx)[nN][oO]/) \ copy_in_global_log = 0; \ }; \ if (copy_in_global_log) \ { \ rst_section(global_test_result ": " $$0); \ while ((rc = (getline line < ($$0 ".log"))) != 0) \ { \ if (rc < 0) \ fatal("failed to read from " $$0 ".log"); \ print line; \ }; \ printf "\n"; \ }; \ close ($$0 ".trs"); \ close ($$0 ".log"); \ }' # Restructured Text title. am__rst_title = { sed 's/.*/ & /;h;s/./=/g;p;x;s/ *$$//;p;g' && echo; } # Solaris 10 'make', and several other traditional 'make' implementations, # pass "-e" to $(SHELL), and POSIX 2008 even requires this. Work around it # by disabling -e (using the XSI extension "set +e") if it's set. am__sh_e_setup = case $$- in *e*) set +e;; esac # Default flags passed to test drivers. am__common_driver_flags = \ --color-tests "$$am__color_tests" \ --enable-hard-errors "$$am__enable_hard_errors" \ --expect-failure "$$am__expect_failure" # To be inserted before the command running the test. Creates the # directory for the log if needed. Stores in $dir the directory # containing $f, in $tst the test, in $log the log. Executes the # developer- defined test setup AM_TESTS_ENVIRONMENT (if any), and # passes TESTS_ENVIRONMENT. Set up options for the wrapper that # will run the test scripts (or their associated LOG_COMPILER, if # thy have one). am__check_pre = \ $(am__sh_e_setup); \ $(am__vpath_adj_setup) $(am__vpath_adj) \ $(am__tty_colors); \ srcdir=$(srcdir); export srcdir; \ case "$@" in \ */*) am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`;; \ *) am__odir=.;; \ esac; \ test "x$$am__odir" = x"." || test -d "$$am__odir" \ || $(MKDIR_P) "$$am__odir" || exit $$?; \ if test -f "./$$f"; then dir=./; \ elif test -f "$$f"; then dir=; \ else dir="$(srcdir)/"; fi; \ tst=$$dir$$f; log='$@'; \ if test -n '$(DISABLE_HARD_ERRORS)'; then \ am__enable_hard_errors=no; \ else \ am__enable_hard_errors=yes; \ fi; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$f[\ \ ]* | *[\ \ ]$$dir$$f[\ \ ]*) \ am__expect_failure=yes;; \ *) \ am__expect_failure=no;; \ esac; \ $(AM_TESTS_ENVIRONMENT) $(TESTS_ENVIRONMENT) # A shell command to get the names of the tests scripts with any registered # extension removed (i.e., equivalently, the names of the test logs, with # the '.log' extension removed). The result is saved in the shell variable # '$bases'. This honors runtime overriding of TESTS and TEST_LOGS. Sadly, # we cannot use something simpler, involving e.g., "$(TEST_LOGS:.log=)", # since that might cause problem with VPATH rewrites for suffix-less tests. # See also 'test-harness-vpath-rewrite.sh' and 'test-trs-basic.sh'. am__set_TESTS_bases = \ bases='$(TEST_LOGS)'; \ bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \ bases=`echo $$bases` RECHECK_LOGS = $(TEST_LOGS) AM_RECURSIVE_TARGETS = check recheck TEST_SUITE_LOG = test-suite.log TEST_EXTENSIONS = .test am__test_logs1 = $(TESTS:=.log) am__test_logs2 = $(am__test_logs1:.log=.log) TEST_LOGS = $(am__test_logs2:.test.log=.log) TEST_LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \ $(TEST_LOG_FLAGS) am__set_b = \ case '$@' in \ */*) \ case '$*' in \ */*) b='$*';; \ *) b=`echo '$@' | sed 's/\.log$$//'`; \ esac;; \ *) \ b='$*';; \ esac am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/test-driver TODO DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = ${SHELL} /home/partimag/dev/partclone/missing aclocal-1.15 AMTAR = $${TAR-tar} AM_DEFAULT_VERBOSITY = 1 AUTOCONF = ${SHELL} /home/partimag/dev/partclone/missing autoconf AUTOHEADER = ${SHELL} /home/partimag/dev/partclone/missing autoheader AUTOMAKE = ${SHELL} /home/partimag/dev/partclone/missing automake-1.15 AWK = gawk CC = gcc CCDEPMODE = depmode=gcc3 CFLAGS = -g -O2 -Wall CPP = gcc -E CPPFLAGS = CYGPATH_W = echo DEFS = -DHAVE_CONFIG_H DEPDIR = .deps ECHO_C = ECHO_N = -n ECHO_T = EGREP = /bin/grep -E EXEEXT = EXT2FS_CFLAGS = -I/usr/include/ext2fs -I/usr/include/et EXT2FS_LIBS = -lext2fs GMSGFMT = /usr/bin/msgfmt GMSGFMT_015 = /usr/bin/msgfmt GREP = /bin/grep INSTALL = /usr/bin/install -c INSTALL_DATA = ${INSTALL} -m 644 INSTALL_PROGRAM = ${INSTALL} INSTALL_SCRIPT = ${INSTALL} INSTALL_STRIP_PROGRAM = $(install_sh) -c -s INTLLIBS = INTL_MACOSX_LIBS = LDFLAGS = LIBICONV = -liconv LIBINTL = LIBOBJS = LIBS = -lpthread LN_S = ln -s LTLIBICONV = -liconv LTLIBINTL = LTLIBOBJS = MAKEINFO = ${SHELL} /home/partimag/dev/partclone/missing makeinfo MKDIR_P = /bin/mkdir -p MSGFMT = /usr/bin/msgfmt MSGFMT_015 = /usr/bin/msgfmt MSGMERGE = /usr/bin/msgmerge NTFS_CFLAGS = NTFS_LIBS = -lpthread -lntfs-3g OBJEXT = o ORIGINAL_CFLAGS = -g -O2 PACKAGE = partclone PACKAGE_BUGREPORT = thomas@nchc.org.tw PACKAGE_NAME = Partclone PACKAGE_STRING = Partclone 0.2.84 PACKAGE_TARNAME = partclone PACKAGE_URL = PACKAGE_VERSION = 0.2.84 PATH_SEPARATOR = : PKG_CONFIG = /usr/bin/pkg-config PKG_CONFIG_LIBDIR = PKG_CONFIG_PATH = POSUB = po RM = /bin/rm SET_MAKE = SHELL = /bin/bash STRIP = USE_NLS = yes UUID_CFLAGS = -I/usr/include/uuid UUID_LIBS = -luuid VERSION = 0.2.84 XGETTEXT = /usr/bin/xgettext XGETTEXT_015 = /usr/bin/xgettext abs_builddir = /home/partimag/dev/partclone/tests abs_srcdir = /home/partimag/dev/partclone/tests abs_top_builddir = /home/partimag/dev/partclone abs_top_srcdir = /home/partimag/dev/partclone ac_ct_CC = gcc am__include = include am__leading_dot = . am__quote = am__tar = $${TAR-tar} chof - "$$tardir" am__untar = $${TAR-tar} xf - bindir = ${exec_prefix}/bin build = x86_64-unknown-linux-gnu build_alias = build_cpu = x86_64 build_os = linux-gnu build_vendor = unknown builddir = . datadir = ${datarootdir} datarootdir = ${prefix}/share docdir = ${datarootdir}/doc/${PACKAGE_TARNAME} dvidir = ${docdir} exec_prefix = ${prefix} host = x86_64-unknown-linux-gnu host_alias = host_cpu = x86_64 host_os = linux-gnu host_vendor = unknown htmldir = ${docdir} includedir = ${prefix}/include infodir = ${datarootdir}/info install_sh = ${SHELL} /home/partimag/dev/partclone/install-sh libdir = ${exec_prefix}/lib libexecdir = ${exec_prefix}/libexec localedir = ${datarootdir}/locale localstatedir = ${prefix}/var mandir = ${datarootdir}/man mkdir_p = /bin/mkdir -p oldincludedir = /usr/include pdfdir = ${docdir} prefix = /usr/local program_transform_name = s,x,x, psdir = ${docdir} runstatedir = ${localstatedir}/run sbindir = ${exec_prefix}/sbin sharedstatedir = ${prefix}/com srcdir = . sysconfdir = ${prefix}/etc target_alias = top_build_prefix = ../ top_builddir = .. top_srcdir = .. TESTS = dd.test $(am__append_1) $(am__append_2) $(am__append_3) \ $(am__append_4) $(am__append_5) $(am__append_6) \ $(am__append_7) $(am__append_8) $(am__append_9) \ $(am__append_10) $(am__append_11) $(am__append_12) \ $(am__append_13) $(am__append_14) CLEANFILES = floppy* all: all-am .SUFFIXES: .SUFFIXES: .log .test .test$(EXEEXT) .trs $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign tests/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign tests/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): tags TAGS: ctags CTAGS: cscope cscopelist: # Recover from deleted '.trs' file; this should ensure that # "rm -f foo.log; make foo.trs" re-run 'foo.test', and re-create # both 'foo.log' and 'foo.trs'. Break the recipe in two subshells # to avoid problems with "make -n". .log.trs: rm -f $< $@ $(MAKE) $(AM_MAKEFLAGS) $< # Leading 'am--fnord' is there to ensure the list of targets does not # expand to empty, as could happen e.g. with make check TESTS=''. am--fnord $(TEST_LOGS) $(TEST_LOGS:.log=.trs): $(am__force_recheck) am--force-recheck: @: $(TEST_SUITE_LOG): $(TEST_LOGS) @$(am__set_TESTS_bases); \ am__f_ok () { test -f "$$1" && test -r "$$1"; }; \ redo_bases=`for i in $$bases; do \ am__f_ok $$i.trs && am__f_ok $$i.log || echo $$i; \ done`; \ if test -n "$$redo_bases"; then \ redo_logs=`for i in $$redo_bases; do echo $$i.log; done`; \ redo_results=`for i in $$redo_bases; do echo $$i.trs; done`; \ if $(am__make_dryrun); then :; else \ rm -f $$redo_logs && rm -f $$redo_results || exit 1; \ fi; \ fi; \ if test -n "$$am__remaking_logs"; then \ echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \ "recursion detected" >&2; \ elif test -n "$$redo_logs"; then \ am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \ fi; \ if $(am__make_dryrun); then :; else \ st=0; \ errmsg="fatal: making $(TEST_SUITE_LOG): failed to create"; \ for i in $$redo_bases; do \ test -f $$i.trs && test -r $$i.trs \ || { echo "$$errmsg $$i.trs" >&2; st=1; }; \ test -f $$i.log && test -r $$i.log \ || { echo "$$errmsg $$i.log" >&2; st=1; }; \ done; \ test $$st -eq 0 || exit 1; \ fi @$(am__sh_e_setup); $(am__tty_colors); $(am__set_TESTS_bases); \ ws='[ ]'; \ results=`for b in $$bases; do echo $$b.trs; done`; \ test -n "$$results" || results=/dev/null; \ all=` grep "^$$ws*:test-result:" $$results | wc -l`; \ pass=` grep "^$$ws*:test-result:$$ws*PASS" $$results | wc -l`; \ fail=` grep "^$$ws*:test-result:$$ws*FAIL" $$results | wc -l`; \ skip=` grep "^$$ws*:test-result:$$ws*SKIP" $$results | wc -l`; \ xfail=`grep "^$$ws*:test-result:$$ws*XFAIL" $$results | wc -l`; \ xpass=`grep "^$$ws*:test-result:$$ws*XPASS" $$results | wc -l`; \ error=`grep "^$$ws*:test-result:$$ws*ERROR" $$results | wc -l`; \ if test `expr $$fail + $$xpass + $$error` -eq 0; then \ success=true; \ else \ success=false; \ fi; \ br='==================='; br=$$br$$br$$br$$br; \ result_count () \ { \ if test x"$$1" = x"--maybe-color"; then \ maybe_colorize=yes; \ elif test x"$$1" = x"--no-color"; then \ maybe_colorize=no; \ else \ echo "$@: invalid 'result_count' usage" >&2; exit 4; \ fi; \ shift; \ desc=$$1 count=$$2; \ if test $$maybe_colorize = yes && test $$count -gt 0; then \ color_start=$$3 color_end=$$std; \ else \ color_start= color_end=; \ fi; \ echo "$${color_start}# $$desc $$count$${color_end}"; \ }; \ create_testsuite_report () \ { \ result_count $$1 "TOTAL:" $$all "$$brg"; \ result_count $$1 "PASS: " $$pass "$$grn"; \ result_count $$1 "SKIP: " $$skip "$$blu"; \ result_count $$1 "XFAIL:" $$xfail "$$lgn"; \ result_count $$1 "FAIL: " $$fail "$$red"; \ result_count $$1 "XPASS:" $$xpass "$$red"; \ result_count $$1 "ERROR:" $$error "$$mgn"; \ }; \ { \ echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" | \ $(am__rst_title); \ create_testsuite_report --no-color; \ echo; \ echo ".. contents:: :depth: 2"; \ echo; \ for b in $$bases; do echo $$b; done \ | $(am__create_global_log); \ } >$(TEST_SUITE_LOG).tmp || exit 1; \ mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG); \ if $$success; then \ col="$$grn"; \ else \ col="$$red"; \ test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG); \ fi; \ echo "$${col}$$br$${std}"; \ echo "$${col}Testsuite summary for $(PACKAGE_STRING)$${std}"; \ echo "$${col}$$br$${std}"; \ create_testsuite_report --maybe-color; \ echo "$$col$$br$$std"; \ if $$success; then :; else \ echo "$${col}See $(subdir)/$(TEST_SUITE_LOG)$${std}"; \ if test -n "$(PACKAGE_BUGREPORT)"; then \ echo "$${col}Please report to $(PACKAGE_BUGREPORT)$${std}"; \ fi; \ echo "$$col$$br$$std"; \ fi; \ $$success || exit 1 check-TESTS: @list='$(RECHECK_LOGS)'; test -z "$$list" || rm -f $$list @list='$(RECHECK_LOGS:.log=.trs)'; test -z "$$list" || rm -f $$list @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) @set +e; $(am__set_TESTS_bases); \ log_list=`for i in $$bases; do echo $$i.log; done`; \ trs_list=`for i in $$bases; do echo $$i.trs; done`; \ log_list=`echo $$log_list`; trs_list=`echo $$trs_list`; \ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$log_list"; \ exit $$?; recheck: all @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) @set +e; $(am__set_TESTS_bases); \ bases=`for i in $$bases; do echo $$i; done \ | $(am__list_recheck_tests)` || exit 1; \ log_list=`for i in $$bases; do echo $$i.log; done`; \ log_list=`echo $$log_list`; \ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \ am__force_recheck=am--force-recheck \ TEST_LOGS="$$log_list"; \ exit $$? .test.log: @p='$<'; \ $(am__set_b); \ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) #.test$(EXEEXT).log: # @p='$<'; \ # $(am__set_b); \ # $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \ # --log-file $$b.log --trs-file $$b.trs \ # $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \ # "$$tst" $(AM_TESTS_FD_REDIRECT) distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am $(MAKE) $(AM_MAKEFLAGS) check-TESTS check: check-am all-am: Makefile installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: -test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS) -test -z "$(TEST_LOGS:.log=.trs)" || rm -f $(TEST_LOGS:.log=.trs) -test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: check-am install-am install-strip .PHONY: all all-am check check-TESTS check-am clean clean-generic \ cscopelist-am ctags-am distclean distclean-generic distdir dvi \ dvi-am html html-am info info-am install install-am \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic pdf \ pdf-am ps ps-am recheck tags-am uninstall uninstall-am .PRECIOUS: Makefile # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: partclone-0.2.86/tests/Makefile.am000066400000000000000000000015041262102574200167750ustar00rootroot00000000000000TESTS = dd.test if ENABLE_FS_TEST if ENABLE_EXTFS TESTS += ext2.test TESTS += ext3.test TESTS += ext4.test endif if ENABLE_BTRFS TESTS += btrfs.test endif if ENABLE_FAT TESTS += fat.test endif if ENABLE_REISERFS TESTS += reiserfs.test endif #if ENABLE_REISER4 #TESTS += reiser4.test #endif if ENABLE_HFSP TESTS += hfsplus.test endif if ENABLE_XFS TESTS += xfs.test endif if ENABLE_EXFAT TESTS += exfat.test endif if ENABLE_F2FS TESTS += f2fs.test endif if ENABLE_NTFS TESTS += ntfs.test endif #if ENABLE_UFS #TESTS += ufs.test #endif #if ENABLE_VMFS #TESTS += vmfs.test #endif if ENABLE_JFS TESTS += jfs.test endif if ENABLE_BTRFS TESTS += btrfs.test endif if ENABLE_EXFAT TESTS += exfat.test endif if ENABLE_NILFS2 TESTS += nilfs2.test endif if ENABLE_NCURSESW TESTS += ncursesw.test endif endif CLEANFILES = floppy* partclone-0.2.86/tests/Makefile.in000066400000000000000000000645021262102574200170150ustar00rootroot00000000000000# Makefile.in generated by automake 1.15 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2014 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ @ENABLE_EXTFS_TRUE@@ENABLE_FS_TEST_TRUE@am__append_1 = ext2.test \ @ENABLE_EXTFS_TRUE@@ENABLE_FS_TEST_TRUE@ ext3.test ext4.test @ENABLE_BTRFS_TRUE@@ENABLE_FS_TEST_TRUE@am__append_2 = btrfs.test @ENABLE_FAT_TRUE@@ENABLE_FS_TEST_TRUE@am__append_3 = fat.test @ENABLE_FS_TEST_TRUE@@ENABLE_REISERFS_TRUE@am__append_4 = reiserfs.test #if ENABLE_REISER4 #TESTS += reiser4.test #endif @ENABLE_FS_TEST_TRUE@@ENABLE_HFSP_TRUE@am__append_5 = hfsplus.test @ENABLE_FS_TEST_TRUE@@ENABLE_XFS_TRUE@am__append_6 = xfs.test @ENABLE_EXFAT_TRUE@@ENABLE_FS_TEST_TRUE@am__append_7 = exfat.test @ENABLE_F2FS_TRUE@@ENABLE_FS_TEST_TRUE@am__append_8 = f2fs.test @ENABLE_FS_TEST_TRUE@@ENABLE_NTFS_TRUE@am__append_9 = ntfs.test #if ENABLE_UFS #TESTS += ufs.test #endif #if ENABLE_VMFS #TESTS += vmfs.test #endif @ENABLE_FS_TEST_TRUE@@ENABLE_JFS_TRUE@am__append_10 = jfs.test @ENABLE_BTRFS_TRUE@@ENABLE_FS_TEST_TRUE@am__append_11 = btrfs.test @ENABLE_EXFAT_TRUE@@ENABLE_FS_TEST_TRUE@am__append_12 = exfat.test @ENABLE_FS_TEST_TRUE@@ENABLE_NILFS2_TRUE@am__append_13 = nilfs2.test @ENABLE_FS_TEST_TRUE@@ENABLE_NCURSESW_TRUE@am__append_14 = ncursesw.test subdir = tests ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/gettext.m4 \ $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__tty_colors_dummy = \ mgn= red= grn= lgn= blu= brg= std=; \ am__color_tests=no am__tty_colors = { \ $(am__tty_colors_dummy); \ if test "X$(AM_COLOR_TESTS)" = Xno; then \ am__color_tests=no; \ elif test "X$(AM_COLOR_TESTS)" = Xalways; then \ am__color_tests=yes; \ elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \ am__color_tests=yes; \ fi; \ if test $$am__color_tests = yes; then \ red=''; \ grn=''; \ lgn=''; \ blu=''; \ mgn=''; \ brg=''; \ std=''; \ fi; \ } am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__recheck_rx = ^[ ]*:recheck:[ ]* am__global_test_result_rx = ^[ ]*:global-test-result:[ ]* am__copy_in_global_log_rx = ^[ ]*:copy-in-global-log:[ ]* # A command that, given a newline-separated list of test names on the # standard input, print the name of the tests that are to be re-run # upon "make recheck". am__list_recheck_tests = $(AWK) '{ \ recheck = 1; \ while ((rc = (getline line < ($$0 ".trs"))) != 0) \ { \ if (rc < 0) \ { \ if ((getline line2 < ($$0 ".log")) < 0) \ recheck = 0; \ break; \ } \ else if (line ~ /$(am__recheck_rx)[nN][Oo]/) \ { \ recheck = 0; \ break; \ } \ else if (line ~ /$(am__recheck_rx)[yY][eE][sS]/) \ { \ break; \ } \ }; \ if (recheck) \ print $$0; \ close ($$0 ".trs"); \ close ($$0 ".log"); \ }' # A command that, given a newline-separated list of test names on the # standard input, create the global log from their .trs and .log files. am__create_global_log = $(AWK) ' \ function fatal(msg) \ { \ print "fatal: making $@: " msg | "cat >&2"; \ exit 1; \ } \ function rst_section(header) \ { \ print header; \ len = length(header); \ for (i = 1; i <= len; i = i + 1) \ printf "="; \ printf "\n\n"; \ } \ { \ copy_in_global_log = 1; \ global_test_result = "RUN"; \ while ((rc = (getline line < ($$0 ".trs"))) != 0) \ { \ if (rc < 0) \ fatal("failed to read from " $$0 ".trs"); \ if (line ~ /$(am__global_test_result_rx)/) \ { \ sub("$(am__global_test_result_rx)", "", line); \ sub("[ ]*$$", "", line); \ global_test_result = line; \ } \ else if (line ~ /$(am__copy_in_global_log_rx)[nN][oO]/) \ copy_in_global_log = 0; \ }; \ if (copy_in_global_log) \ { \ rst_section(global_test_result ": " $$0); \ while ((rc = (getline line < ($$0 ".log"))) != 0) \ { \ if (rc < 0) \ fatal("failed to read from " $$0 ".log"); \ print line; \ }; \ printf "\n"; \ }; \ close ($$0 ".trs"); \ close ($$0 ".log"); \ }' # Restructured Text title. am__rst_title = { sed 's/.*/ & /;h;s/./=/g;p;x;s/ *$$//;p;g' && echo; } # Solaris 10 'make', and several other traditional 'make' implementations, # pass "-e" to $(SHELL), and POSIX 2008 even requires this. Work around it # by disabling -e (using the XSI extension "set +e") if it's set. am__sh_e_setup = case $$- in *e*) set +e;; esac # Default flags passed to test drivers. am__common_driver_flags = \ --color-tests "$$am__color_tests" \ --enable-hard-errors "$$am__enable_hard_errors" \ --expect-failure "$$am__expect_failure" # To be inserted before the command running the test. Creates the # directory for the log if needed. Stores in $dir the directory # containing $f, in $tst the test, in $log the log. Executes the # developer- defined test setup AM_TESTS_ENVIRONMENT (if any), and # passes TESTS_ENVIRONMENT. Set up options for the wrapper that # will run the test scripts (or their associated LOG_COMPILER, if # thy have one). am__check_pre = \ $(am__sh_e_setup); \ $(am__vpath_adj_setup) $(am__vpath_adj) \ $(am__tty_colors); \ srcdir=$(srcdir); export srcdir; \ case "$@" in \ */*) am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`;; \ *) am__odir=.;; \ esac; \ test "x$$am__odir" = x"." || test -d "$$am__odir" \ || $(MKDIR_P) "$$am__odir" || exit $$?; \ if test -f "./$$f"; then dir=./; \ elif test -f "$$f"; then dir=; \ else dir="$(srcdir)/"; fi; \ tst=$$dir$$f; log='$@'; \ if test -n '$(DISABLE_HARD_ERRORS)'; then \ am__enable_hard_errors=no; \ else \ am__enable_hard_errors=yes; \ fi; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$f[\ \ ]* | *[\ \ ]$$dir$$f[\ \ ]*) \ am__expect_failure=yes;; \ *) \ am__expect_failure=no;; \ esac; \ $(AM_TESTS_ENVIRONMENT) $(TESTS_ENVIRONMENT) # A shell command to get the names of the tests scripts with any registered # extension removed (i.e., equivalently, the names of the test logs, with # the '.log' extension removed). The result is saved in the shell variable # '$bases'. This honors runtime overriding of TESTS and TEST_LOGS. Sadly, # we cannot use something simpler, involving e.g., "$(TEST_LOGS:.log=)", # since that might cause problem with VPATH rewrites for suffix-less tests. # See also 'test-harness-vpath-rewrite.sh' and 'test-trs-basic.sh'. am__set_TESTS_bases = \ bases='$(TEST_LOGS)'; \ bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \ bases=`echo $$bases` RECHECK_LOGS = $(TEST_LOGS) AM_RECURSIVE_TARGETS = check recheck TEST_SUITE_LOG = test-suite.log TEST_EXTENSIONS = @EXEEXT@ .test am__test_logs1 = $(TESTS:=.log) am__test_logs2 = $(am__test_logs1:@EXEEXT@.log=.log) TEST_LOGS = $(am__test_logs2:.test.log=.log) TEST_LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \ $(TEST_LOG_FLAGS) am__set_b = \ case '$@' in \ */*) \ case '$*' in \ */*) b='$*';; \ *) b=`echo '$@' | sed 's/\.log$$//'`; \ esac;; \ *) \ b='$*';; \ esac am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/test-driver TODO DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXT2FS_CFLAGS = @EXT2FS_CFLAGS@ EXT2FS_LIBS = @EXT2FS_LIBS@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ LDFLAGS = @LDFLAGS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LN_S = @LN_S@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ NTFS_CFLAGS = @NTFS_CFLAGS@ NTFS_LIBS = @NTFS_LIBS@ OBJEXT = @OBJEXT@ ORIGINAL_CFLAGS = @ORIGINAL_CFLAGS@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ POSUB = @POSUB@ RM = @RM@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ USE_NLS = @USE_NLS@ UUID_CFLAGS = @UUID_CFLAGS@ UUID_LIBS = @UUID_LIBS@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ TESTS = dd.test $(am__append_1) $(am__append_2) $(am__append_3) \ $(am__append_4) $(am__append_5) $(am__append_6) \ $(am__append_7) $(am__append_8) $(am__append_9) \ $(am__append_10) $(am__append_11) $(am__append_12) \ $(am__append_13) $(am__append_14) CLEANFILES = floppy* all: all-am .SUFFIXES: .SUFFIXES: .log .test .test$(EXEEXT) .trs $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign tests/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign tests/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): tags TAGS: ctags CTAGS: cscope cscopelist: # Recover from deleted '.trs' file; this should ensure that # "rm -f foo.log; make foo.trs" re-run 'foo.test', and re-create # both 'foo.log' and 'foo.trs'. Break the recipe in two subshells # to avoid problems with "make -n". .log.trs: rm -f $< $@ $(MAKE) $(AM_MAKEFLAGS) $< # Leading 'am--fnord' is there to ensure the list of targets does not # expand to empty, as could happen e.g. with make check TESTS=''. am--fnord $(TEST_LOGS) $(TEST_LOGS:.log=.trs): $(am__force_recheck) am--force-recheck: @: $(TEST_SUITE_LOG): $(TEST_LOGS) @$(am__set_TESTS_bases); \ am__f_ok () { test -f "$$1" && test -r "$$1"; }; \ redo_bases=`for i in $$bases; do \ am__f_ok $$i.trs && am__f_ok $$i.log || echo $$i; \ done`; \ if test -n "$$redo_bases"; then \ redo_logs=`for i in $$redo_bases; do echo $$i.log; done`; \ redo_results=`for i in $$redo_bases; do echo $$i.trs; done`; \ if $(am__make_dryrun); then :; else \ rm -f $$redo_logs && rm -f $$redo_results || exit 1; \ fi; \ fi; \ if test -n "$$am__remaking_logs"; then \ echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \ "recursion detected" >&2; \ elif test -n "$$redo_logs"; then \ am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \ fi; \ if $(am__make_dryrun); then :; else \ st=0; \ errmsg="fatal: making $(TEST_SUITE_LOG): failed to create"; \ for i in $$redo_bases; do \ test -f $$i.trs && test -r $$i.trs \ || { echo "$$errmsg $$i.trs" >&2; st=1; }; \ test -f $$i.log && test -r $$i.log \ || { echo "$$errmsg $$i.log" >&2; st=1; }; \ done; \ test $$st -eq 0 || exit 1; \ fi @$(am__sh_e_setup); $(am__tty_colors); $(am__set_TESTS_bases); \ ws='[ ]'; \ results=`for b in $$bases; do echo $$b.trs; done`; \ test -n "$$results" || results=/dev/null; \ all=` grep "^$$ws*:test-result:" $$results | wc -l`; \ pass=` grep "^$$ws*:test-result:$$ws*PASS" $$results | wc -l`; \ fail=` grep "^$$ws*:test-result:$$ws*FAIL" $$results | wc -l`; \ skip=` grep "^$$ws*:test-result:$$ws*SKIP" $$results | wc -l`; \ xfail=`grep "^$$ws*:test-result:$$ws*XFAIL" $$results | wc -l`; \ xpass=`grep "^$$ws*:test-result:$$ws*XPASS" $$results | wc -l`; \ error=`grep "^$$ws*:test-result:$$ws*ERROR" $$results | wc -l`; \ if test `expr $$fail + $$xpass + $$error` -eq 0; then \ success=true; \ else \ success=false; \ fi; \ br='==================='; br=$$br$$br$$br$$br; \ result_count () \ { \ if test x"$$1" = x"--maybe-color"; then \ maybe_colorize=yes; \ elif test x"$$1" = x"--no-color"; then \ maybe_colorize=no; \ else \ echo "$@: invalid 'result_count' usage" >&2; exit 4; \ fi; \ shift; \ desc=$$1 count=$$2; \ if test $$maybe_colorize = yes && test $$count -gt 0; then \ color_start=$$3 color_end=$$std; \ else \ color_start= color_end=; \ fi; \ echo "$${color_start}# $$desc $$count$${color_end}"; \ }; \ create_testsuite_report () \ { \ result_count $$1 "TOTAL:" $$all "$$brg"; \ result_count $$1 "PASS: " $$pass "$$grn"; \ result_count $$1 "SKIP: " $$skip "$$blu"; \ result_count $$1 "XFAIL:" $$xfail "$$lgn"; \ result_count $$1 "FAIL: " $$fail "$$red"; \ result_count $$1 "XPASS:" $$xpass "$$red"; \ result_count $$1 "ERROR:" $$error "$$mgn"; \ }; \ { \ echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" | \ $(am__rst_title); \ create_testsuite_report --no-color; \ echo; \ echo ".. contents:: :depth: 2"; \ echo; \ for b in $$bases; do echo $$b; done \ | $(am__create_global_log); \ } >$(TEST_SUITE_LOG).tmp || exit 1; \ mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG); \ if $$success; then \ col="$$grn"; \ else \ col="$$red"; \ test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG); \ fi; \ echo "$${col}$$br$${std}"; \ echo "$${col}Testsuite summary for $(PACKAGE_STRING)$${std}"; \ echo "$${col}$$br$${std}"; \ create_testsuite_report --maybe-color; \ echo "$$col$$br$$std"; \ if $$success; then :; else \ echo "$${col}See $(subdir)/$(TEST_SUITE_LOG)$${std}"; \ if test -n "$(PACKAGE_BUGREPORT)"; then \ echo "$${col}Please report to $(PACKAGE_BUGREPORT)$${std}"; \ fi; \ echo "$$col$$br$$std"; \ fi; \ $$success || exit 1 check-TESTS: @list='$(RECHECK_LOGS)'; test -z "$$list" || rm -f $$list @list='$(RECHECK_LOGS:.log=.trs)'; test -z "$$list" || rm -f $$list @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) @set +e; $(am__set_TESTS_bases); \ log_list=`for i in $$bases; do echo $$i.log; done`; \ trs_list=`for i in $$bases; do echo $$i.trs; done`; \ log_list=`echo $$log_list`; trs_list=`echo $$trs_list`; \ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$log_list"; \ exit $$?; recheck: all @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) @set +e; $(am__set_TESTS_bases); \ bases=`for i in $$bases; do echo $$i; done \ | $(am__list_recheck_tests)` || exit 1; \ log_list=`for i in $$bases; do echo $$i.log; done`; \ log_list=`echo $$log_list`; \ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \ am__force_recheck=am--force-recheck \ TEST_LOGS="$$log_list"; \ exit $$? .test.log: @p='$<'; \ $(am__set_b); \ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) @am__EXEEXT_TRUE@.test$(EXEEXT).log: @am__EXEEXT_TRUE@ @p='$<'; \ @am__EXEEXT_TRUE@ $(am__set_b); \ @am__EXEEXT_TRUE@ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \ @am__EXEEXT_TRUE@ --log-file $$b.log --trs-file $$b.trs \ @am__EXEEXT_TRUE@ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \ @am__EXEEXT_TRUE@ "$$tst" $(AM_TESTS_FD_REDIRECT) distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am $(MAKE) $(AM_MAKEFLAGS) check-TESTS check: check-am all-am: Makefile installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: -test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS) -test -z "$(TEST_LOGS:.log=.trs)" || rm -f $(TEST_LOGS:.log=.trs) -test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: check-am install-am install-strip .PHONY: all all-am check check-TESTS check-am clean clean-generic \ cscopelist-am ctags-am distclean distclean-generic distdir dvi \ dvi-am html html-am info info-am install install-am \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic pdf \ pdf-am ps ps-am recheck tags-am uninstall uninstall-am .PRECIOUS: Makefile # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: partclone-0.2.86/tests/TODO000066400000000000000000000000231262102574200154240ustar00rootroot00000000000000ufs.test vmfs.test partclone-0.2.86/tests/_common000066400000000000000000000042001262102574200163070ustar00rootroot00000000000000#!/bin/bash break_debug=0 logfile='test.log' img='floppy.img' raw='floppy.raw' dd_bs=1024 normal_size=$((1024*1024*1)) floppy_size=1024 current_dir=`pwd` ptldir="../src" ptlinfo=$ptldir/partclone.info ptlchkimg=$ptldir/partclone.chkimg ptlrestore=$ptldir/partclone.restore mkfs_option_for_ext2='-F' mkfs_option_for_ext3='-F' mkfs_option_for_ext4='-F' mkfs_option_for_reiserfs='-q' mkfs_option_for_reiser4='-f -y' mkfs_option_for_ntfs='-f -F' mkfs_option_for_jfs='-q' mkfs_option_for_xfs='-f' mkfs_option_for_btrfs='-f' mkfs_option_for_fat12='-F 12' mkfs_option_for_fat16='-F 16' mkfs_option_for_fat32='-F 32' #mkfs_option_for_minix='-3' ## file system # mountable for writing file system mountable_fs="ext2 ext3 ext4 vfat exfat minix jfs xfs reiserfs ntfs btrfs hfsplus f2fs nilfs2" # vmfs file system can't format, can mount read-only # ufs mkfs.ufs can't format special file as partition extra_fs="vmfs ufs" # foramtable file system reiser4 can't mount, ufs read-only formatable_fs="$mountable_fs reiser4" _check_root(){ if [[ $UID -ne 0 ]]; then echo "$0 must be run as root" exit 1 fi } _check_return_code(){ if [ $? != 0 ]; then echo "return code fail" exit fi } _ptlbreak(){ if [ $break_debug -ne 0 ];then echo "continue test process(Y/n)? default yes" read con if [ "$con" == "n" ];then exit 1 fi fi } _test_size(){ fs=$1 case "$fs" in fat12) normal_size=$((1024*8)) ;; fat16) normal_size=$((1024*32)) ;; fat32|fat|vfat) normal_size=$((1024*128)) ;; esac echo $normal_size } _findmkfs(){ fs=$1 case "$fs" in fat12|fat16|fat32|fat|vfat) fs="vfat" ;; esac mkfs_path=$(locate mkfs.$fs|grep sbin|head -n 1) if [ -z $mkfs_path ]; then echo >&2 "can't find mkfs.$fs" exit 1 fi echo $mkfs_path } _ptlname(){ fs=$1 case "$fs" in ext2|ext3|ext4|extfs) ptl="$ptldir/partclone.extfs" ;; fat16|fat12|fat32|fat|vfat) ptl="$ptldir/partclone.fat" ;; hfsplus) ptl="$ptldir/partclone.hfsp" ;; *) ptl="$ptldir/partclone.$fs" esac if [ ! -f $ptl ]; then echo >&2 "can't find $ptl" exit 1 fi echo "$ptl" } partclone-0.2.86/tests/btrfs.test000077500000000000000000000000541262102574200167640ustar00rootroot00000000000000#!/bin/bash ./mini_clone_restore_test btrfs partclone-0.2.86/tests/data_clone_restore_test000077500000000000000000000042131262102574200215620ustar00rootroot00000000000000#!/bin/bash . _common break_debug=0 manual_fs=$1 test_fs=$mountable_fs dd_count=$normal_size [ -z $manual_fs ] || test_fs=$manual_fs source_partition="/dev/sdb1" target_partition="/dev/sdc1" source_mountpoint="/test/source" target_mountpoint="/test/target" data_pool="/test/datapool/" chfile="/test/checksum.log" cchfile="/test/checksum_test.log" #main for fs in $test_fs; do echo -e "Advanced $fs test" echo -e "==========================\n" mkdir -p $source_mountpoint $target_mountpoint $data_pool umount $target_mountpoint $source_mountpoint set -e ptlfs=$(_ptlname $fs) mkfs=$(_findmkfs $fs) logfile="/test/clone-$fs.log" echo -e "\nformat $source_partition as $fs partition\n" echo -e " mkfs.$fs `eval echo "$"mkfs_option_for_$fs""` $source_partition\n" _ptlbreak $mkfs `eval echo "$"mkfs_option_for_$fs""` $source_partition _check_return_code echo -e "\nprepare data to clone\n" _ptlbreak mount -t $fs $source_partition $source_mountpoint set +e # rsync error while rsync to vfat # rsync error while rsync to exfat # rsync -arl $data_pool $source_mountpoint # use cp -r cp -r $data_pool/* $source_mountpoint set -e sync pushd $source_mountpoint find . -type f -exec md5sum '{}' \; > $chfile popd umount $source_mountpoint echo -e "\nmd5sum done\n" echo -e "\ndevice to device clone, $source_partition to $target_partition\n" echo -e " $ptlfs -d -b -s $source_partition -o $target_partition -L $logfile\n" _ptlbreak $ptlfs -q -d -b -s $source_partition -o $target_partition -L $logfile _check_return_code echo -e "\ncheck data\n" _ptlbreak mount -t $fs $target_partition $target_mountpoint pushd $target_mountpoint md5sum --quiet -c $chfile 2>&1 > $cchfile popd umount $target_mountpoint echo -e "\ndone\n" _check_return_code echo -e "\nclear tmp files\n" _ptlbreak set +e umount $target_mountpoint $source_mountpoint rm -r $target_mountpoint $source_mountpoint $logfile $chfile $cchfile _check_return_code echo -e "\n$fs test ok\n" done echo -e "\nFinish!\n\n" partclone-0.2.86/tests/dd.test000077500000000000000000000024171262102574200162400ustar00rootroot00000000000000#!/bin/bash set -e . _common fs="dd" ptlfs="../src/partclone.dd" dd_count=$((normal_size/2)) echo -e "partclone.dd test" echo -e "====================\n" _ptlbreak [ -f $raw ] && rm $raw echo -e "create raw file $raw\n" echo -e " dd if=/dev/urandom of=$raw bs=$dd_bs count=$dd_count\n" dd if=/dev/urandom of=$raw bs=$dd_bs count=$dd_count smd5=$(md5sum $raw) echo -e "\nclone $raw to $img\n" [ -f $img ] && rm $img echo -e " $ptlfs -d -s $raw -O $img -F -L $logfile\n" _ptlbreak $ptlfs -d -s $raw -O $img -F -L $logfile _check_return_code echo -e "\ncreate raw file $raw for restore\n" _ptlbreak [ -f $raw ] && rm $raw echo -e " dd if=/dev/zero of=$raw bs=$dd_bs count=$dd_count\n" dd if=/dev/zero of=$raw bs=$dd_bs count=$dd_count echo -e "\nrestore $img to $raw\n" #echo "$ptlrestore -s $img -O $raw -C -F -L $logfile\n" echo -e " $ptlfs -d -s $img -O $raw -F -L $logfile\n" _ptlbreak #$ptlrestore -s $img -O $raw -C -F -L $logfile $ptlfs -d -s $img -O $raw -F -L $logfile _check_return_code nmd5=$(md5sum $raw) if [ "X$smd5" == "X$nmd5" ]; then echo -e "\n$fs test ok\n" echo -e "\nclear tmp files $img $raw $logfile $md5\n" _ptlbreak rm -f $img $raw $logfile $md5 else echo -e "\n$fs test fail\n" echo -e "\nmd5 checksum error ($smd5, $nmd5)\n" fi partclone-0.2.86/tests/domain.test000077500000000000000000000026421262102574200171200ustar00rootroot00000000000000#!/bin/bash set -e . _common ## file system fs="ext3" dd_count=$normal_size break_debug=0 #main ddraw="raw2" ptlfs=$(_ptlname $fs) mkfs=$(_findmkfs $fs) echo -e "domain logfile option test" echo -e "====================\n" echo -e "\ncreate raw file $raw\n" _ptlbreak [ -f $raw ] && rm $raw echo -e " dd if=/dev/zero of=$raw bs=$dd_bs count=$dd_count\n" dd if=/dev/zero of=$raw bs=$dd_bs count=$dd_count echo -e "\nformat $raw as $fs raw partition\n" echo -e " mkfs.$fs `eval echo "$"mkfs_option_for_$fs""` $raw\n" _ptlbreak $mkfs `eval echo "$"mkfs_option_for_$fs""` $raw echo -e "\nclone $raw and output domain file\n" [ -f $img ] && rm $img echo -e " $ptlfs -d -D -s $raw -O $img -F -L $logfile\n" _ptlbreak time $ptlfs -d -D -s $raw -O $img -F -L $logfile _check_return_code echo -e "\ncreate raw file $ddraw for restore\n" _ptlbreak [ -f $ddraw ] && rm $ddraw echo -e " dd if=/dev/zero of=$ddraw bs=$dd_bs count=$dd_count\n" dd if=/dev/zero of=$ddraw bs=$dd_bs count=$dd_count echo -e "\nddrescue from $raw to $ddraw with option --domain-logfile=$img \n" echo -e " ddrescue --domain-logfile=$img $raw $ddraw \n" _ptlbreak ddrescue --domain-logfile=$img $raw $ddraw _check_return_code _ptlbreak md5sum $raw | sed s/$raw/$ddraw/ | md5sum -c _check_return_code echo -e "\nddrescue domain logfile test ok\n" echo -e "\nclear tmp files $img $raw $logfile $md5 $ddraw\n" _ptlbreak #rm -f $img $raw $logfile $md5 $ddraw partclone-0.2.86/tests/exfat.test000077500000000000000000000000541262102574200167530ustar00rootroot00000000000000#!/bin/bash ./mini_clone_restore_test exfat partclone-0.2.86/tests/ext2.test000077500000000000000000000000531262102574200165250ustar00rootroot00000000000000#!/bin/bash ./mini_clone_restore_test ext2 partclone-0.2.86/tests/ext3.test000077500000000000000000000000531262102574200165260ustar00rootroot00000000000000#!/bin/bash ./mini_clone_restore_test ext3 partclone-0.2.86/tests/ext4.test000077500000000000000000000000531262102574200165270ustar00rootroot00000000000000#!/bin/bash ./mini_clone_restore_test ext4 partclone-0.2.86/tests/f2fs.test000077500000000000000000000000531262102574200165030ustar00rootroot00000000000000#!/bin/bash ./mini_clone_restore_test f2fs partclone-0.2.86/tests/failmbr000077500000000000000000000002671262102574200163100ustar00rootroot00000000000000#!/bin/bash fail_mbr_dir="../fail-mbr" hd $fail_mbr_dir/fail-mbr.bin > fail-mbr.hex hd $fail_mbr_dir/fail-mbr.bin.orig > fail-mbr.hex.orig diff fail-mbr.hex.orig fail-mbr.hex || true partclone-0.2.86/tests/fat.test000077500000000000000000000001541262102574200164170ustar00rootroot00000000000000#!/bin/bash ./mini_clone_restore_test fat12 ./mini_clone_restore_test fat16 ./mini_clone_restore_test fat32 partclone-0.2.86/tests/hfsplus.test000077500000000000000000000000561262102574200173320ustar00rootroot00000000000000#!/bin/bash ./mini_clone_restore_test hfsplus partclone-0.2.86/tests/imager.test000077500000000000000000000020541262102574200171120ustar00rootroot00000000000000#!/bin/bash set -e . _common fs="imager" ptlfs="../src/partclone.imager" dd_count=$((normal_size/2)) echo -e "partclone.imager test" echo -e "====================\n" echo -e "create raw file $raw and save as partclone image file\n" _ptlbreak [ -f $raw ] && rm $raw echo -e " dd if=/dev/zero of=$raw bs=$dd_bs count=$dd_count\n" dd if=/dev/zero of=$raw bs=$dd_bs count=$dd_count echo -e "\nclone $raw to $img\n" [ -f $img ] && rm $img echo -e " $ptlfs -d -c -s $raw -O $img -F -L $logfile\n" _ptlbreak $ptlfs -d -c -s $raw -O $img -F -L $logfile _check_return_code echo -e "\ncreate raw file $raw for restore\n" _ptlbreak [ -f $raw ] && rm $raw echo -e " dd if=/dev/zero of=$raw bs=$dd_bs count=$dd_count\n" dd if=/dev/zero of=$raw bs=$dd_bs count=$dd_count echo -e "\nrestore $img to $raw\n" echo -e " $ptlrestore -s $img -O $raw -C -F -L $logfile\n" _ptlbreak $ptlrestore -s $img -O $raw -C -F -L $logfile _check_return_code echo -e "\nimager test ok\n" echo -e "\nclear tmp files $img $raw $logfile $md5\n" _ptlbreak rm -f $img $raw $logfile $md5 partclone-0.2.86/tests/info.test000077500000000000000000000030241262102574200165770ustar00rootroot00000000000000#!/bin/bash set -e . _common break_debug=0 manual_fs="ext2" dd_count=$normal_size [ -z $manual_fs ] || test_fs=$manual_fs echo -e "partclone.info test" echo -e "===================\n" #main for fs in $test_fs; do ptlfs=$(_ptlname $fs) mkfs=$(_findmkfs $fs) echo -e "create raw file $raw\n" _ptlbreak [ -f $raw ] && rm $raw echo -e " dd if=/dev/zero of=$raw bs=$dd_bs count=$dd_count\n" dd if=/dev/zero of=$raw bs=$dd_bs count=$dd_count echo -e "\nformat $raw as $fs raw partition\n" echo -e " mkfs.$fs `eval echo "$"mkfs_option_for_$fs""` $raw\n" _ptlbreak $mkfs `eval echo "$"mkfs_option_for_$fs""` $raw echo -e "\nclone $raw to $img\n" [ -f $img ] && rm $img echo -e " $ptlfs -d -c -s $raw -O $img -F -L $logfile\n" _ptlbreak $ptlfs -d -c -s $raw -O $img -F -L $logfile _check_return_code echo -e "\nprint image header\n" echo -e " $ptlinfo -s $img -L $logfile\n" _ptlbreak $ptlinfo -s $img -L $logfile _check_return_code echo -e "\nprint image header from stdin image\n" echo -e " cat $img | $ptlinfo -s - -L $logfile\n" _ptlbreak cat $img | $ptlinfo -s - -L $logfile _check_return_code echo -e "\ncheck logfile\n" echo -e "\ncat $logfile\n" _ptlbreak cat $logfile _check_return_code set +e echo -e "\ngive no options\n" $ptlinfo set -e echo -e "\ninfo test ok\n" echo -e "\nclear tmp files $img $raw $logfile $md5\n" _ptlbreak rm -f $img $raw $logfile $md5 done partclone-0.2.86/tests/jfs.test000077500000000000000000000000521262102574200164240ustar00rootroot00000000000000#!/bin/bash ./mini_clone_restore_test jfs partclone-0.2.86/tests/mini_clone_restore_test000077500000000000000000000032321262102574200216050ustar00rootroot00000000000000#!/bin/bash set -e . _common manual_fs=$1 test_fs=$formatable_fs [ -z $manual_fs ] || test_fs=$manual_fs #main for fs in $test_fs; do echo -e "Basic $fs test" echo -e "==========================\n" ptlfs=$(_ptlname $fs) mkfs=$(_findmkfs $fs) dd_count=$(_test_size $fs) echo -e "\ncreate raw file $raw\n" _ptlbreak [ -f $raw ] && rm $raw echo -e " dd if=/dev/zero of=$raw bs=$dd_bs count=$dd_count\n" dd if=/dev/zero of=$raw bs=$dd_bs count=$dd_count echo -e "\n\nformat $raw as $fs raw partition\n" echo -e " $mkfs `eval echo "$"mkfs_option_for_$fs""` $raw\n" _ptlbreak $mkfs `eval echo "$"mkfs_option_for_$fs""` $raw echo -e "\nclone $raw to $img\n" [ -f $img ] && rm $img echo -e " $ptlfs -d -c -s $raw -O $img -F -L $logfile\n" _ptlbreak $ptlfs -d -c -s $raw -O $img -F -L $logfile _check_return_code echo -e "\n\ndo image checking\n" echo -e " $ptlchkimg -s $img -L $logfile\n" _ptlbreak $ptlchkimg -s $img -L $logfile _check_return_code echo -e "\n\ncreate raw file $raw for restore\n" _ptlbreak [ -f $raw ] && rm $raw echo -e " dd if=/dev/zero of=$raw bs=$dd_bs count=$dd_count\n" dd if=/dev/zero of=$raw bs=$dd_bs count=$dd_count echo -e "\n\nrestore $img to $raw\n" echo -e " $ptlrestore -s $img -O $raw -C -F -L $logfile\n" _ptlbreak $ptlrestore -s $img -O $raw -C -F -L $logfile _check_return_code echo -e "\n\n$fs test ok\n" echo -e "\nclear tmp files $img $raw $logfile $md5\n" _ptlbreak rm -f $img $raw $logfile $md5 echo -e "\nfile system $fs test done\n" done echo -e "\nFinish!\n" partclone-0.2.86/tests/minix.test000077500000000000000000000000541262102574200167700ustar00rootroot00000000000000#!/bin/bash ./mini_clone_restore_test minix partclone-0.2.86/tests/ncursesw.test000077500000000000000000000012141262102574200175140ustar00rootroot00000000000000#!/bin/bash set -e . _common fs="dd" ptlfs="../src/partclone.dd" dd_count=$((normal_size/2)) echo -e "Ncurses test" echo -e "====================\n" echo -e "\ncreate raw file $raw\n" _ptlbreak [ -f $raw ] && rm $raw echo -e " dd if=/dev/zero of=$raw bs=$dd_bs count=$dd_count\n" dd if=/dev/zero of=$raw bs=$dd_bs count=$dd_count echo -e "\nclone $raw to $img\n" [ -f $img ] && rm $img echo -e " $ptlfs -d -N -s $raw -O $img -F -L $logfile\n" _ptlbreak $ptlfs -d -N -s $raw -O $img -F -L $logfile _check_return_code echo -e "\nncursesw test ok\n" echo -e "\nclear tmp files $img $raw $logfile $md5\n" _ptlbreak rm -f $img $raw $logfile $md5 partclone-0.2.86/tests/nilfs2.test000077500000000000000000000040341262102574200170430ustar00rootroot00000000000000#!/bin/bash set -e . _common manual_fs="nilfs2" _check_root test_fs=$formatable_fs dd_count=$normal_size [ -z $manual_fs ] || test_fs=$manual_fs #main for fs in $test_fs; do echo -e "Basic $fs test" echo -e "==========================\n" ptlfs=$(_ptlname $fs) mkfs=$(_findmkfs $fs) echo -e "\ncreate raw file $raw\n" _ptlbreak [ -f $raw ] && rm $raw echo -e " dd if=/dev/zero of=$raw bs=$dd_bs count=$dd_count\n" dd if=/dev/zero of=$raw bs=$dd_bs count=$dd_count echo -e "\n\nformat $raw as $fs raw partition\n" echo -e " mkfs.$fs `eval echo "$"mkfs_option_for_$fs""` $raw\n" _ptlbreak $mkfs `eval echo "$"mkfs_option_for_$fs""` $raw loop_device=$(losetup -f) echo -e "losetup $loop_device $raw" losetup $loop_device $raw echo -e "\nclone $loop_device to $img\n" [ -f $img ] && rm $img echo -e " $ptlfs -d -c -s $loop_device -O $img -F -L $logfile\n" _ptlbreak $ptlfs -d -c -s $loop_device -O $img -F -L $logfile echo -e "detach $loop_device" losetup -d $loop_device _check_return_code echo -e "\n\ndo image checking\n" echo -e " $ptlchkimg -s $img -L $logfile\n" _ptlbreak $ptlchkimg -s $img -L $logfile _check_return_code echo -e "\n\ncreate raw file $raw for restore\n" _ptlbreak [ -f $raw ] && rm $raw echo -e " dd if=/dev/zero of=$raw bs=$dd_bs count=$dd_count\n" dd if=/dev/zero of=$raw bs=$dd_bs count=$dd_count loop_device=$(losetup -f) echo -e "losetup $loop_device $raw" losetup $loop_device $raw echo -e "\n\nrestore $img to $loop_device\n" echo -e " $ptlrestore -s $img -O $loop_device -C -F -L $logfile\n" _ptlbreak $ptlrestore -s $img -O $loop_device -C -F -L $logfile echo -e "detach $loop_device" losetup -d $loop_device _check_return_code echo -e "\n\n$fs test ok\n" echo -e "\nclear tmp files $img $raw $logfile $md5\n" _ptlbreak rm -f $img $raw $logfile $md5 echo -e "\nfile system $fs test done\n" done echo -e "\nFinish!\n" partclone-0.2.86/tests/note.test000077500000000000000000000012321262102574200166100ustar00rootroot00000000000000#!/bin/bash set -e . _common fs="dd" ptlfs="../src/partclone.dd" dd_count=$((normal_size/2)) echo -e "partclone.dd test" echo -e "====================\n" _ptlbreak [ -f $raw ] && rm $raw echo -e "create raw file $raw\n" echo -e " dd if=/dev/urandom of=$raw bs=$dd_bs count=$dd_count\n" dd if=/dev/urandom of=$raw bs=$dd_bs count=$dd_count smd5=$(md5sum $raw) echo -e "\nclone $raw to $img\n" [ -f $img ] && rm $img echo -e " $ptlfs -d -s $raw -O $img -F -L $logfile -n note test\n" _ptlbreak $ptlfs -d -s $raw -O $img -F -L $logfile -n "note test" _check_return_code $ptlfs -d -N -s $raw -O $img -F -L $logfile -n "note test" _check_return_code echo "done" partclone-0.2.86/tests/ntfs.test000077500000000000000000000000531262102574200166150ustar00rootroot00000000000000#!/bin/bash ./mini_clone_restore_test ntfs partclone-0.2.86/tests/offset.test000077500000000000000000000024641262102574200171410ustar00rootroot00000000000000#!/bin/bash set -e . _common disk_size=$((512*1024576)) row_A_file=$0.row_A row_B_file=$0.row_B OFFSET=1048576 ptlfs=$(_ptlname "extfs") _check_root echo -e "partclone offset option test" echo -e "===========================\n" echo -e "\ncreate tw row file and setup as loop device\n" dd if=/dev/zero of=$row_A_file count=1 bs=$disk_size dd if=/dev/zero of=$row_B_file count=1 bs=$(($disk_size+$OFFSET)) part_loop_device=$(losetup -f) losetup $part_loop_device $row_A_file offset_loop_device=$(losetup -f) losetup $offset_loop_device $row_B_file sleep 2 echo -e "\nformet loop device $part_loop_device\n" mkfs.ext3 $part_loop_device _ptlbreak echo -e "\n clone $part_loop_device to $offset_loop_device with offset option\n" echo -e " $ptlfs -d -b -s $part_loop_device -o $offset_loop_device --offset=$OFFSET\n" $ptlfs -d -b -s $part_loop_device -o $offset_loop_device --offset=$OFFSET _check_return_code echo -e "\nmount $offset_loop_device with offset option and check return code\n" set +e echo -e " mount -o offset=$OFFSET $offset_loop_device /mnt\n" mount -o offset=$OFFSET $offset_loop_device /mnt _check_return_code mount umount /mnt mount | grep loop losetup -d $part_loop_device losetup -d $offset_loop_device set -e echo -e "\nremove row file\n" rm -f $row_A_file $row_B_file echo -e "\noffset test done\n" partclone-0.2.86/tests/prestable.test000077500000000000000000000027721262102574200176360ustar00rootroot00000000000000#!/bin/bash PARTCLONE_PATH="/home/thomas/partclone" REPORT_PATH="/test/report" CURRENT_PATH="/test/report/current" if [[ $EUID -ne 0 ]]; then echo "This script must be run as root" 1>&2 exit 1 fi mkdir -p $REPORT_PATH function_test="dd.test ncursesw.test quiet.test imager.test info.test offset.test restore_to_raw.test domain.test note.test" empty_part_test="mini_clone_restore_test" data_part_test="data_clone_restore_test" pushd $PARTCLONE_PATH make clean autoreconf ./configure --enable-all --enable-ncursesw make popd pushd $PARTCLONE_PATH/tests ver=$(../src/partclone.extfs -v | grep Partclone|awk '{print $4}' | sed s/\(//g) ver=$(echo ${ver:0:6}) REPORT_PATH="/test/report/$ver" if [ -d $REPORT_PATH ];then echo "$REPORT_PATH exist" echo "exit" exit 1 fi mkdir -p $REPORT_PATH echo "start $function_test test" for fun in $function_test; do echo "@@@ start $func test" ./$fun 2>&1 | tee $REPORT_PATH/func-`date +%F`-$fun.md echo "@@@ end $func test" done echo "end $function_test test" echo "start $empty_part_test test" for fs in $empty_part_test; do echo "@@@ start $fs test" ./$fs 2>&1 | tee $REPORT_PATH/mini-`date +%F`-$fs.md echo "@@@ end $fs test" done echo "end $empty_part_test test" echo "start $data_part_test test" for fs in $data_part_test; do echo "@@@ start $fs test" ./$fs 2>&1 | tee $REPORT_PATH/data-`date +%F`-$fs.md echo "@@@ end $fs test" done echo "end data $empty_part_test test" rm $CURRENT_PATH ln -s $REPORT_PATH $CURRENT_PATH popd partclone-0.2.86/tests/quiet.test000077500000000000000000000030301262102574200167700ustar00rootroot00000000000000#!/bin/bash set -e . _common ## file system fs="ext3" dd_count=$normal_size break_debug=0 #main ptlfs=$(_ptlname $fs) mkfs=$(_findmkfs $fs) echo -e "quiet option test" echo -e "====================\n" echo -e "\ncreate raw file $raw\n" _ptlbreak [ -f $raw ] && rm $raw echo -e " dd if=/dev/zero of=$raw bs=$dd_bs count=$dd_count\n" dd if=/dev/zero of=$raw bs=$dd_bs count=$dd_count echo -e "\nformat $raw as $fs raw partition\n" echo -e " mkfs.$fs `eval echo "$"mkfs_option_for_$fs""` $raw\n" _ptlbreak $mkfs `eval echo "$"mkfs_option_for_$fs""` $raw echo -e "\nclone $raw to $img\n" [ -f $img ] && rm $img echo -e " $ptlfs -d -c -s $raw -O $img -F -L $logfile\n" _ptlbreak time $ptlfs -d -c -s $raw -O $img -F -L $logfile _check_return_code echo -e "\nquiet mode\n" echo -e " $ptlfs -d -q -c -s $raw -O $img -F -L $logfile\n" _ptlbreak time $ptlfs -d -q -c -s $raw -O $img -F -L $logfile _check_return_code echo -e "\ndo image checking\n" echo -e " $ptlchkimg -s $img -L $logfile\n" _ptlbreak $ptlchkimg -s $img -L $logfile _check_return_code echo -e "\ncreate raw file $raw for restore\n" _ptlbreak [ -f $raw ] && rm $raw echo -e " dd if=/dev/zero of=$raw bs=$dd_bs count=$dd_count\n" dd if=/dev/zero of=$raw bs=$dd_bs count=$dd_count echo -e "\nrestore $img to $raw\n" echo -e " $ptlrestore -s $img -O $raw -C -F -L $logfile\n" _ptlbreak $ptlrestore -s $img -O $raw -C -F -L $logfile _check_return_code echo -e "\nquiet test ok\n" echo -e "\nclear tmp files $img $raw $logfile $md5\n" _ptlbreak rm -f $img $raw $logfile $md5 partclone-0.2.86/tests/reiser4.test000077500000000000000000000000561262102574200172230ustar00rootroot00000000000000#!/bin/bash ./mini_clone_restore_test reiser4 partclone-0.2.86/tests/reiserfs.test000077500000000000000000000000571262102574200174710ustar00rootroot00000000000000#!/bin/bash ./mini_clone_restore_test reiserfs partclone-0.2.86/tests/restore_to_raw.test000077500000000000000000000023651262102574200207110ustar00rootroot00000000000000#!/bin/bash set -e . _common ## file system fs="ext3" dd_count=$normal_size break_debug=0 #main loop_device="loop_floppy.raw" ptlfs=$(_ptlname $fs) mkfs=$(_findmkfs $fs) echo -e "restore_to_raw option test" echo -e "====================\n" echo -e "\ncreate raw file $raw\n" _ptlbreak [ -f $raw ] && rm $raw echo -e " dd if=/dev/zero of=$raw bs=$dd_bs count=$dd_count\n" dd if=/dev/zero of=$raw bs=$dd_bs count=$dd_count echo -e "\nformat $raw as $fs raw partition\n" echo -e " mkfs.$fs `eval echo "$"mkfs_option_for_$fs""` $raw\n" _ptlbreak $mkfs `eval echo "$"mkfs_option_for_$fs""` $raw echo -e "\nclone $raw to $img\n" [ -f $img ] && rm $img echo -e " $ptlfs -d -c -s $raw -O $img -F -L $logfile\n" _ptlbreak time $ptlfs -d -c -s $raw -O $img -F -L $logfile _check_return_code echo -e "\nrestore $img to $raw file(raw format)\n" echo -e " $ptlfs -r -s $img -o $loop_device -L $logfile --restore_raw_file \n" _ptlbreak $ptlfs -r -F -s $img -o $loop_device -L $logfile --restore_raw_file _check_return_code echo -e "\ntest row file by blkid?\n" echo -e "\nblkid $raw\n" _ptlbreak blkid $raw _ptlbreak echo -e "\nrestore to raw test ok\n" echo -e "\nclear tmp files $img $raw $logfile $md5\n" _ptlbreak rm -f $img $raw $logfile $md5 $loop_device partclone-0.2.86/tests/xfs.test000077500000000000000000000000521262102574200164420ustar00rootroot00000000000000#!/bin/bash ./mini_clone_restore_test xfs partclone-0.2.86/toolbox000077500000000000000000000070151262102574200152160ustar00rootroot00000000000000#! /bin/sh ## toolbox for the Partclone ## initial copied from VLC ## Authors: thomas thomas at nchc dot org dot tw ### ### Get a sane environment, just in case ### LC_ALL=C export LC_ALL LANG=C export LANG ## ## Give help ## help() { cat << EOF recognized flags are: --update-po update translation files --update-log update Changelog files from git --update-btrfs update source of btrfs --update-version generate src/version.h EOF exit 1 } ### ### argument check ### if test "$1" = "" then help fi case "$1" in --update-po) action=po ;; --update-btrfs) action=btrfs ;; --update-log) action=changelog ;; --update-version) action=version ;; --help) help ;; *) echo "$0: unknown option $1" help ;; esac shift ## ## Update the potfiles because no one ever does it ## if test "${action}" = "po" then # find out the source files echo "WARNING: you should run \"make update-po\" instead!" >&2 cd po make update-po exit $? fi ## ## Update the source of btrfs ## if test "${action}" = "btrfs" then BTRFS_SOURCE="bitops.h ctree.h extent_io.c inode-item.c math.h radix-tree.c root-tree.c ulist.c volumes.c btrfsck.h dir-item.c extent_io.h inode-map.c print-tree.c radix-tree.h send.h ulist.h volumes.h btrfs-list.c disk-io.c extent-tree.c ioctl.h print-tree.h raid6.c send-stream.c utils.c btrfs-list.h disk-io.h file-item.c kerncompat.h qgroup.c rbtree.c send-stream.h utils.h crc32c.c free-space-cache.c list.h qgroup.h rbtree.h send-utils.c utils-lib.c rbtree-utils.c crc32c.h extent-cache.c free-space-cache.h list_sort.c qgroup-verify.c repair.c send-utils.h uuid-tree.c ctree.c extent-cache.h hash.h list_sort.h qgroup-verify.h repair.h transaction.h version.h rbtree-utils.h rbtree_augmented.h" echo "cp $BTRFS_SOURCE partclone/src/btrfs/" fi ## ## update Changelog from SVN ## #if test "${action}" = "changelog" #then # echo "Would you want to export svn log to ChangeLog(y/N)?" # read log # case "$log" in # [yY] | [Yy][Ee][Ss] ) # if which svn2cl 2>&1 >/dev/null ; then # echo "please input svn password to export svn log." # svn2cl --reparagraph --break-before-msg=2 # else # echo "WARNING: you should install subversion-tools firstly." # fi # ;; # esac # exit $? #fi # ## ## Create version file ## if test "${action}" = "version" then scriptdir=`dirname "$0"` file="$scriptdir/src/version.h" GIT_REPOSITORY=`git remote -v | grep partclone` GIT_REVISION=`git log -1 | grep ^commit | sed 's/commit //'` #GIT_REVISION_UPSTREAM=`git log master -1 | grep commit | sed 's/commit //'` git_ver="none" if [ "${GIT_REPOSITORY}" = "" ]; then echo "not git repository?" exit 0 fi #if [ "${GIT_REVISION_UPSTREAM}" != "" ]; then # git_ver=$GIT_REVISION_UPSTREAM #el if [ "${GIT_REVISION}" != "" ]; then git_ver=$GIT_REVISION else git_ver="none" fi if [ "$git_ver" != "none" ]; then echo "create ${file}" cat > ${file} << EOF /* DO NOT EDIT THIS FILE - IT IS REGENERATED AT EVERY COMPILE - * IT GIVES BETTER TRACKING OF DEVELOPMENT VERSIONS * WHETHER THEY ARE BUILT BY OTHERS OR DURING DEVELOPMENT OR FOR THE * OFFICIAL PARTCLONE RELEASES. */ #define git_version "$git_ver" EOF fi exit 0 fi if test "${action}" = "changelog" then # get source code from Jim Meyering at # http://git.mymadcat.com/index.php/p/tracker/source/tree/master/gitlog-to-changelog perl gitlog-to-changelog --since 1999-01-01 > ChangeLog fi